My Project
TXLib.h
Go to the documentation of this file.
1 //=================================================================================================================
2 // TXLib.h - Библиотека Тупого Художника (The Dumb Artist Library, TX Library, TXLib) - (C) Ilya Dedinsky
3 //=================================================================================================================
4 // [These sections are for folding control in Code::Blocks] [$Date: 2024-06-23 22:37:05 +0400 $]
5 // [Best viewed with "Fold all on file open" option enabled] [Best screen/page width = 120 chars]
6 //
7 // [If RUSSIAN CHARS below are UNREADABLE, check this file codepage. It should be CP1251, NOT UTF-8 etc.]
8 //{ [Use RELOAD options in your IDE or editor (CLion / Visual Studio Code / ...), and do NOT use Convert.]
9 //=================================================================================================================
102 // $Copyright: (C) Ded (Ilya Dedinsky, http://txlib.ru) <mail@txlib.ru> $
103 //-----------------------------------------------------------------------------------------------------------------
110 //}
111 //=================================================================================================================
112 
113 #if !defined (__TXLIB_H_INCLUDED) // <<< THE CODE IS HERE, UNFOLD IT <<<
114 #define __TXLIB_H_INCLUDED
115 
116 //-----------------------------------------------------------------------------------------------------------------
117 //{ Version information and configuration
118 //-----------------------------------------------------------------------------------------------------------------
119 
120 //{----------------------------------------------------------------------------------------------------------------
142 //}----------------------------------------------------------------------------------------------------------------
144 
145 #define _TX_VER _TX_v_FROM_CVS ($VersionInfo: , TXLib.h, 00173a, 173, 2024-06-23 22:37:05 +0400, "Ded (Ilya Dedinsky, http://txlib.ru) <mail@txlib.ru>", $)
146 #define _TX_VERSION _TX_V_FROM_CVS ($VersionInfo: , TXLib.h, 00173a, 173, 2024-06-23 22:37:05 +0400, "Ded (Ilya Dedinsky, http://txlib.ru) <mail@txlib.ru>", $)
147 #define _TX_AUTHOR _TX_A_FROM_CVS ($VersionInfo: , TXLib.h, 00173a, 173, 2024-06-23 22:37:05 +0400, "Ded (Ilya Dedinsky, http://txlib.ru) <mail@txlib.ru>", $)
148 
150 #define _TX_v_FROM_CVS(_1,file,ver,rev,date,auth,_2) ((0x##ver##u << 16) | 0x##rev##u)
151 #define _TX_V_FROM_CVS(_1,file,ver,rev,date,auth,_2) "TXLib [Ver: " #ver ", Rev: " #rev ", Date: " #date "]"
152 #define _TX_A_FROM_CVS(_1,file,ver,rev,date,auth,_2) "Copyright (C) " auth
154 
156 //{----------------------------------------------------------------------------------------------------------------
163 //}----------------------------------------------------------------------------------------------------------------
164 
165 #if !defined (_TX_MODULE)
166  #define _TX_MODULE "TXLib"
167 #endif
168 
169 //{----------------------------------------------------------------------------------------------------------------
173 //}----------------------------------------------------------------------------------------------------------------
174 
175 #if defined (__GNUC__)
176 
177  #define _GCC_VER ( __GNUC__*100 + __GNUC_MINOR__*10 + __GNUC_PATCHLEVEL__ )
178 
179  #define __TX_COMPILER__ "GNU g++ " TX_QUOTE (__GNUC__) "." \
180  TX_QUOTE (__GNUC_MINOR__) "." \
181  TX_QUOTE (__GNUC_PATCHLEVEL__) \
182  ", std=" TX_QUOTE (__cplusplus)
183 
184 #elif defined (__clang__) || defined (__clang_major__)
185 
186  #define _CLANG_VER ( __clang_major__*100 + __clang_minor__*10 + __clang_patchlevel__ )
187 
188  #define __TX_COMPILER__ "Clang " TX_QUOTE (__clang_major__) "." \
189  TX_QUOTE (__clang_minor__) "." \
190  TX_QUOTE (__clang_patchlevel__) \
191  ", std=" TX_QUOTE (__cplusplus)
192 #elif defined (_MSC_VER)
193 
194  #define __TX_COMPILER__ "MSVS " TX_QUOTE (_MSC_VER) \
195  ", std=" TX_QUOTE (__cplusplus)
196 
197 #elif defined (__INTEL_COMPILER)
198 
199  #define __TX_COMPILER__ "Intel C++ " TX_QUOTE (__INTEL_COMPILER) \
200  ", std=" TX_QUOTE (__cplusplus)
201 #else
202 
203  #define __TX_COMPILER__ "Unknown C++, std=" TX_QUOTE (__cplusplus)
204  #endif
205 
207 
208 #define TX_QUOTE(sym) _TX_QUOTE (sym)
209 #define _TX_QUOTE(sym) #sym
210 
211 #define TX_JOIN(sym1, sym2) _TX_JOIN (sym1, sym2)
212 #define _TX_JOIN(sym1, sym2) sym1 ## sym2
213 
215 
216 #if (__cplusplus >= 201103L) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013
217 
218  #define _TX_CPP11 1
219  #endif
220 
221 #if (__cplusplus >= 201103L) || defined (_MSC_VER) && (_MSC_VER >= 1900) // MSVC 2015
222 
223  #define _TX_CPP11_MSVC15 1
224  #endif
225 
226 //{----------------------------------------------------------------------------------------------------------------
230 //}----------------------------------------------------------------------------------------------------------------
231 
232 #if !defined (NDEBUG) && defined (_DEBUG)
233  #define _TX_BUILDMODE "DEBUG"
234 
235 #elif !defined (NDEBUG) && !defined (_DEBUG)
236  #define _TX_BUILDMODE "Debug"
237 
238 #elif defined (NDEBUG)
239  #define _TX_BUILDMODE "Release"
240 #endif
241 
242 //{----------------------------------------------------------------------------------------------------------------
246 //}----------------------------------------------------------------------------------------------------------------
247 
248 #define __TX_FILELINE__ __FILE__ ":" TX_QUOTE (__LINE__)
249 
250 //{----------------------------------------------------------------------------------------------------------------
258 //}----------------------------------------------------------------------------------------------------------------
259 
260 #if defined (__GNUC__) || defined (__clang__) || defined (__clang_major__)
261  #define __TX_FUNCTION__ __PRETTY_FUNCTION__
262 
263 #elif defined (__FUNCSIG__)
264  #define __TX_FUNCTION__ __FUNCSIG__
265 
266 #elif defined (__FUNCTION__)
267  #define __TX_FUNCTION__ __FUNCTION__
268 
269 #elif defined (__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)
270  #define __TX_FUNCTION__ __FUNCTION__
271 
272 #elif defined (__BORLANDC__) && (__BORLANDC__ >= 0x550)
273  #define __TX_FUNCTION__ __FUNC__
274 
275 #elif defined (__cplusplus) && (__cplusplus >= 199711L)
276  #define __TX_FUNCTION__ __func__
277 
278 #elif defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
279  #define __TX_FUNCTION__ __func__
280 
281 #elif defined (__PYTHON__)
282  #error No Python. No. Using parseltongue languages can lead you to Slytherin.
283 
284 #else
285  #define __TX_FUNCTION__ "(" __TX_FILELINE__ ")"
286 
287 #endif
288 
289 #if !defined (__func__) && defined (__FUNCTION__)
290  #define __func__ __FUNCTION__
291 
292 #endif
293 
294 //}
295 //-----------------------------------------------------------------------------------------------------------------
296 
297 //-----------------------------------------------------------------------------------------------------------------
298 //{ Compiler- and platform-specific
300 //-----------------------------------------------------------------------------------------------------------------
302 
303 #if !defined (__cplusplus)
304 
305  #ifdef __GNUC__
306  #error
307  #error ---------------------------------------------------------------------------------------
308  #endif
309  #error TXLib.h: Must use C++ to compile TXLib.h. Now you are using C only.
310  #error
311  #error CHECK source file EXTENSION. Maybe it is ".C". It must be ".CPP".
312  #error If your file is named, for example, "Untitled.C", go to menu [File],
313  #error then [Save As] and rename it to "Untitled.CPP". Please do NOT use spaces.
314  #error ---------------------------------------------------------------------------------------
315  #error
316 
317 #endif
318 
319 //-----------------------------------------------------------------------------------------------------------------
320 
321 #if !defined (WIN32) && !defined (__WIN32__) && !defined(_WIN32) && !defined(_WIN32_WINNT) && !defined (__CYGWIN__)
322 
323  #ifdef __GNUC__
324  #error
325  #error ---------------------------------------------------------------------------------------
326  #endif
327  #error TXLib.h: Windows (MSVC/Win32 or GCC/MinGW or Cygwin) is the only supported OS, sorry.
328  #error
329  #error In Linux or MacOS, you should write your own TXLib and share it with your friends, or use wine.
330  #error ---------------------------------------------------------------------------------------
331  #error
332 
333 #endif
334 
335 //-----------------------------------------------------------------------------------------------------------------
336 
337 #if defined (UNICODE) || defined (_UNICODE)
338 
339  #ifdef __GNUC__
340  #warning TXLib.h: Disabling the UNICODE
341  #endif
342 
343  #undef UNICODE // Burn Unicode, burn
344  #undef _UNICODE
345 
346  #if defined (_WINDOWS_H) || defined (_INC_WINDOWS) || defined (_WINDOWS_) || defined (__WINDOWS__)
347 
348  #ifdef __GNUC__
349  #error
350  #error ---------------------------------------------------------------------------------------
351  #endif
352  #error TXLib.h: Should include "TXLib.h" BEFORE or INSTEAD of <Windows.h> in UNICODE mode.
353  #error
354  #error REARRANGE your #include directives, or DISABLE the UNICODE mode by #undef UNICODE/_UNICODE.
355  #error ---------------------------------------------------------------------------------------
356  #error
357 
358  #endif
359 
360 #endif
361 
362 //-----------------------------------------------------------------------------------------------------------------
363 
364 #if defined (__STRICT_ANSI__) && (_GCC_VER < 1120) // Try to extend strict ANSI rules
365 
366  #undef __STRICT_ANSI__
367  #define __STRICT_ANSI__UNDEFINED
368 
369  #if defined (_STRING_H_) || defined (_INC_STRING) || defined (_STDIO_H_) || defined (_INC_STDIO)
370 
371  #ifdef __GNUC__
372  #error
373  #error ---------------------------------------------------------------------------------------
374  #endif
375  #error TXLib.h: Should include "TXLib.h" BEFORE <string.h> or <stdio.h> in Strict ANSI mode.
376  #error
377  #error REARRANGE your #include directives, or DISABLE ANSI-compliancy by #undef __STRICT_ANSI__.
378  #error ---------------------------------------------------------------------------------------
379  #error
380 
381  #endif
382 
383 #endif
384 
385 //-----------------------------------------------------------------------------------------------------------------
386 
387 #if defined (__GNUC__)
388 
389  #pragma GCC diagnostic ignored "-Wpragmas"
390 
391  #pragma GCC diagnostic warning "-Wall"
392  #pragma GCC diagnostic warning "-Weffc++"
393  #pragma GCC diagnostic warning "-Wextra"
394 
395  #pragma GCC diagnostic warning "-Waggressive-loop-optimizations"
396  #pragma GCC diagnostic warning "-Walloc-zero"
397  #pragma GCC diagnostic warning "-Walloca"
398  #pragma GCC diagnostic warning "-Walloca-larger-than=8192"
399  #pragma GCC diagnostic warning "-Warray-bounds"
400  #pragma GCC diagnostic warning "-Wcast-align"
401  #pragma GCC diagnostic warning "-Wcast-qual"
402  #pragma GCC diagnostic warning "-Wchar-subscripts"
403  #pragma GCC diagnostic warning "-Wconditionally-supported"
404  #pragma GCC diagnostic warning "-Wconversion"
405  #pragma GCC diagnostic warning "-Wctor-dtor-privacy"
406  #pragma GCC diagnostic warning "-Wdangling-else"
407  #pragma GCC diagnostic warning "-Wduplicated-branches"
408  #pragma GCC diagnostic warning "-Wempty-body"
409  #pragma GCC diagnostic warning "-Wfloat-equal"
410  #pragma GCC diagnostic warning "-Wformat-nonliteral"
411  #pragma GCC diagnostic warning "-Wformat-overflow=2"
412  #pragma GCC diagnostic warning "-Wformat-security"
413  #pragma GCC diagnostic warning "-Wformat-signedness"
414  #pragma GCC diagnostic warning "-Wformat-truncation=2"
415  #pragma GCC diagnostic warning "-Wformat=2"
416  #pragma GCC diagnostic warning "-Wlarger-than=8192"
417  #pragma GCC diagnostic warning "-Wlogical-op"
418  #pragma GCC diagnostic warning "-Wmismatched-tags"
419  #pragma GCC diagnostic warning "-Wmissing-declarations"
420  #pragma GCC diagnostic warning "-Wnarrowing"
421  #pragma GCC diagnostic warning "-Wnon-virtual-dtor"
422  #pragma GCC diagnostic warning "-Wnonnull"
423  #pragma GCC diagnostic warning "-Wopenmp-simd"
424  #pragma GCC diagnostic warning "-Woverloaded-virtual"
425  #pragma GCC diagnostic warning "-Wpacked"
426  #pragma GCC diagnostic warning "-Wpointer-arith"
427  #pragma GCC diagnostic warning "-Wredundant-decls"
428  #pragma GCC diagnostic warning "-Wredundant-tags"
429  #pragma GCC diagnostic warning "-Wrestrict"
430  #pragma GCC diagnostic warning "-Wshadow"
431  #pragma GCC diagnostic warning "-Wsign-promo"
432  #pragma GCC diagnostic warning "-Wstack-usage=8192"
433  #pragma GCC diagnostic warning "-Wstrict-aliasing"
434  #pragma GCC diagnostic warning "-Wstrict-null-sentinel"
435  #pragma GCC diagnostic warning "-Wstrict-overflow=2"
436  #pragma GCC diagnostic warning "-Wstringop-overflow=4"
437  #pragma GCC diagnostic warning "-Wsuggest-attribute=noreturn"
438  #pragma GCC diagnostic warning "-Wsuggest-final-methods"
439  #pragma GCC diagnostic warning "-Wsuggest-final-types"
440  #pragma GCC diagnostic warning "-Wsuggest-override"
441  #pragma GCC diagnostic warning "-Wswitch-default"
442  #pragma GCC diagnostic warning "-Wswitch-enum"
443  #pragma GCC diagnostic warning "-Wsync-nand"
444  #pragma GCC diagnostic warning "-Wundef"
445  #pragma GCC diagnostic warning "-Wunused"
446  #pragma GCC diagnostic warning "-Wvarargs"
447  #pragma GCC diagnostic warning "-Wvla-larger-than=8192"
448 
449  #pragma GCC diagnostic error "-Wsizeof-array-argument"
450 
451  #pragma GCC diagnostic ignored "-Waddress"
452  #pragma GCC diagnostic ignored "-Winline"
453  #pragma GCC diagnostic ignored "-Wliteral-suffix"
454  #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
455  #pragma GCC diagnostic ignored "-Wnonnull-compare"
456  #pragma GCC diagnostic ignored "-Wold-style-cast"
457  #pragma GCC diagnostic ignored "-Wunreachable-code"
458  #pragma GCC diagnostic ignored "-Wunused-const-variable"
459  #pragma GCC diagnostic ignored "-Wunused-function"
460  #pragma GCC diagnostic ignored "-Wvariadic-macros"
461 
462  #pragma GCC diagnostic warning "-Wpragmas"
463 
464  //{ These warning settings for TXLib.h only and will be re-enabled at end of file:
465 
466  #pragma GCC push_options
467  #pragma GCC diagnostic push
468 
469  #pragma GCC diagnostic ignored "-Wpragmas"
470 
471  #pragma GCC diagnostic ignored "-Wpedantic"
472  #pragma GCC diagnostic ignored "-Waddress"
473  #pragma GCC diagnostic ignored "-Warray-bounds"
474  #pragma GCC diagnostic ignored "-Wclobbered"
475  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
476  #pragma GCC diagnostic ignored "-Wfloat-equal"
477  #pragma GCC diagnostic ignored "-Wformat-nonliteral"
478  #pragma GCC diagnostic ignored "-Wlarger-than="
479  #pragma GCC diagnostic ignored "-Wmisleading-indentation"
480  #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
481  #pragma GCC diagnostic ignored "-Wredundant-decls"
482  #pragma GCC diagnostic ignored "-Wshadow"
483  #pragma GCC diagnostic ignored "-Wsign-conversion"
484  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
485  #pragma GCC diagnostic ignored "-Wsuggest-override"
486  #pragma GCC diagnostic ignored "-Wunused-label" // Just for fun in _txCanvas_OnCmdAbout()
487  #pragma GCC diagnostic ignored "-Wunused-value"
488  #pragma GCC diagnostic ignored "-Wformat-zero-length"
489  #pragma GCC diagnostic ignored "-Wpacked-not-aligned"
490  #pragma GCC optimize "no-strict-aliasing"
491 
492  #pragma GCC diagnostic warning "-Wpragmas"
493 
494  #if defined (__CYGWIN__) && !defined (_TX_TESTING)
495  #pragma GCC system_header // This is not a fair play, but this is the only way to deal with Cygwin :(
496  #endif
497 
498  //}
499 
500  #define _tx_thread __thread
501  #define _tx_decltype(value) __decltype (value)
502 
503  #define _FORTIFY_SOURCE 2
504 
505  #ifndef MINGW_HAS_SECURE_API
506  #define MINGW_HAS_SECURE_API 1
507  #endif
508 
509  #if defined (TX_USE_SFML)
510  #define _GLIBCXX_NDEBUG
511  #endif
512 
513  #ifndef _GLIBCXX_NDEBUG // TXLib enables _GLIBCXX_DEBUG by default. When using third-party libraries
514  #define _GLIBCXX_DEBUG // compiled without _GLIBCXX_DEBUG (SFML, for example), #define _GLIBCXX_NDEBUG
515  #define _GLIBCXX_DEBUG_PEDANTIC // *before* including TXLib.h.
516  #endif
517 
518  #if defined (_WIN64) // removed in x86 because printf ("%g", double) failure, this prints 0 always
519  #ifndef __USE_MINGW_ANSI_STDIO
520  #define __USE_MINGW_ANSI_STDIO 1
521  #endif
522  #endif
523 
524  template <typename T>
525  inline T _txNOP (T value) { return value; } // To suppress performance warnings in assert etc.
526 
527  // From MinGW\include\float.h which is replaced by MinGW\lib\gcc\i686-pc-mingw32\x.x.x\include\float.h
528  extern "C" __declspec (dllimport) unsigned __cdecl _controlfp (unsigned control, unsigned mask);
529  extern "C" void __cdecl _fpreset ();
530 
531 #else
532 
533  #define __attribute__( attr )
534  #define _txNOP( value ) ( value )
535 
536 #endif
537 
538 //-----------------------------------------------------------------------------------------------------------------
539 
540 #if defined (__clang__) || defined (__clang_major__)
541 
542  #pragma clang diagnostic ignored "-Wunknown-pragmas"
543 
544  #pragma clang diagnostic warning "-Wall"
545  #pragma clang diagnostic warning "-Weffc++"
546  #pragma clang diagnostic warning "-Wextra"
547 
548  #pragma clang diagnostic warning "-Wcast-qual"
549  #pragma clang diagnostic warning "-Wchar-subscripts"
550  #pragma clang diagnostic warning "-Wconversion"
551  #pragma clang diagnostic warning "-Wctor-dtor-privacy"
552  #pragma clang diagnostic warning "-Wempty-body"
553  #pragma clang diagnostic warning "-Wfloat-equal"
554  #pragma clang diagnostic warning "-Wformat"
555  #pragma clang diagnostic warning "-Wformat-nonliteral"
556  #pragma clang diagnostic warning "-Wformat-security"
557  #pragma clang diagnostic warning "-Wmissing-declarations"
558  #pragma clang diagnostic warning "-Wnon-virtual-dtor"
559  #pragma clang diagnostic warning "-Woverloaded-virtual"
560  #pragma clang diagnostic warning "-Wpacked"
561  #pragma clang diagnostic warning "-Wpointer-arith"
562  #pragma clang diagnostic warning "-Wredundant-decls"
563  #pragma clang diagnostic warning "-Wshadow"
564  #pragma clang diagnostic warning "-Wsign-promo"
565  #pragma clang diagnostic warning "-Wstrict-aliasing"
566  #pragma clang diagnostic warning "-Wstrict-overflow"
567  #pragma clang diagnostic warning "-Wswitch-default"
568  #pragma clang diagnostic warning "-Wswitch-enum"
569  #pragma clang diagnostic warning "-Wunused"
570 
571  #pragma clang diagnostic ignored "-Winvalid-source-encoding"
572  #pragma clang diagnostic ignored "-Wunused-const-variable"
573  #pragma clang diagnostic ignored "-Wunused-variable"
574 
575  #pragma clang diagnostic warning "-Wunknown-pragmas"
576 
577  //{ These warning settings for TXLib.h only and will be re-enabled at end of file:
578 
579  #pragma clang diagnostic push
580 
581  #pragma clang diagnostic ignored "-Wunknown-pragmas"
582 
583  #pragma clang diagnostic ignored "-Wpedantic"
584  #pragma clang diagnostic ignored "-Wcast-align"
585  #pragma clang diagnostic ignored "-Wfloat-conversion"
586  #pragma clang diagnostic ignored "-Wmicrosoft-cast"
587  #pragma clang diagnostic ignored "-Wmisleading-indentation"
588  #pragma clang diagnostic ignored "-Wmissing-braces"
589  #pragma clang diagnostic ignored "-Wmissing-field-initializers"
590  #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
591  #pragma clang diagnostic ignored "-Wsign-compare"
592  #pragma clang diagnostic ignored "-Wsign-conversion"
593  #pragma clang diagnostic ignored "-Wstring-plus-int"
594  #pragma clang diagnostic ignored "-Wundef"
595  #pragma clang diagnostic ignored "-Wundefined-bool-conversion"
596  #pragma clang diagnostic ignored "-Wunused-function"
597  #pragma clang diagnostic ignored "-Wunused-value"
598  #pragma clang diagnostic ignored "-Wvariadic-macros"
599 
600  #pragma clang diagnostic warning "-Wunknown-pragmas"
601 
602  //{ CLang-Tidy options
603  //
604  // *,-cert-dcl50-cpp,-cert-dcl58-cpp,-cert-err52-cpp,-cert-err58-cpp,-cert-flp30-c,-cert-msc30-c,-cert-msc32-c,
605  // -cert-msc50-cpp,-cert-msc51-cpp,-clang-analyzer-core.DivideZero,-cppcoreguidelines-avoid-c-arrays,
606  // -cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-macro-usage,
607  // -cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-no-malloc,
608  // -cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,
609  // -cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-cstyle-cast,-cppcoreguidelines-pro-type-union-access,
610  // -cppcoreguidelines-pro-type-vararg,-fuchsia-default-arguments-calls,-fuchsia-default-arguments-declarations,
611  // -fuchsia-overloaded-operator,-google-build-using-namespace,-google-global-names-in-headers,-google-runtime-int,
612  // -google-readability-braces-around-statements,-google-readability-casting,-google-readability-namespace-comments,
613  // -hicpp-avoid-c-arrays,-hicpp-avoid-goto,-hicpp-braces-around-statements,-hicpp-deprecated-headers,-hicpp-no-array-decay,
614  // -hicpp-signed-bitwise,-hicpp-use-equals-delete,-hicpp-use-nullptr,-hicpp-vararg,-llvm-include-order,-hicpp-no-malloc,
615  // -llvm-namespace-comment,-misc-non-private-member-variables-in-classes,-modernize-avoid-c-arrays,-modernize-use-auto,
616  // -modernize-deprecated-headers,-modernize-raw-string-literal,-modernize-use-default-member-init,-hicpp-use-auto,
617  // -modernize-use-equals-delete,-modernize-use-nullptr,-modernize-use-trailing-return-type,-modernize-use-using,
618  // -readability-braces-around-statements,-readability-else-after-return,-readability-implicit-bool-conversion,
619  // -readability-isolate-declaration,-readability-magic-numbers,-readability-named-parameter,-modernize-loop-convert
620  //}
621 
622  //}
623 
624 #endif
625 
626 //-----------------------------------------------------------------------------------------------------------------
627 
628 #if defined (_MSC_VER)
629 
630  #pragma warning (push, 4) // Set maximum warning level. This 'push' is to set the level only. It will NOT be popped.
631 
632  #pragma warning (disable: 4616) // #pragma warning: warning number 'n' not a valid compiler warning
633 
634  #pragma warning (disable: 4514) // Unreferenced inline function has been removed
635  #pragma warning (disable: 4710) // Function not inlined
636  #pragma warning (disable: 4786) // Identifier was truncated to '255' characters in the debug information
637 
638  #pragma warning (error: 4715) // Not all control paths return a value
639 
640  #pragma warning (default: 4616) // #pragma warning: warning number 'n' not a valid compiler warning //-V665
641 
642  #pragma warning (disable: 26473) // Don't cast between pointer types where the source type and the target type are the same (type.1).
643  #pragma warning (disable: 26475) // Do not use function style C-casts (es.49).
644  #pragma warning (disable: 26477) // Use 'nullptr' rather than 0 or NULL (es.47).
645  #pragma warning (disable: 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
646  #pragma warning (disable: 26826) // Don't use C-style variable arguments (f.55).
647 
648  // These warning settings for TXLib.h only and will be re-enabled at end of file:
649 
650  #pragma warning (push)
651 
652  #pragma warning (disable: 4616) // #pragma warning: warning number 'n' not a valid compiler warning
653 
654  #pragma warning (disable: 4091) // 'typedef': ignored on left of '...' when no variable is declared
655  #pragma warning (disable: 4124) // Using __fastcall with stack checking is ineffective
656  #pragma warning (disable: 4127) // Conditional expression is constant
657  #pragma warning (disable: 4200) // Nonstandard extension used: zero-sized array in struct/union
658  #pragma warning (disable: 4201) // Nonstandard extension used: nameless struct/union
659  #pragma warning (disable: 4351) // New behavior: elements of array will be default initialized
660  #pragma warning (disable: 4480) // Nonstandard extension used: specifying underlying type for enum 'type'
661  #pragma warning (disable: 4481) // Nonstandard extension used: override specifier 'override'
662  #pragma warning (disable: 4555) // Result of expression not used
663  #pragma warning (disable: 4611) // Interaction between '_setjmp' and C++ object destruction is non-portable
664  #pragma warning (disable: 5045) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
665  #pragma warning (disable: 6269) // Possibly incorrect order of operations: dereference ignored
666  #pragma warning (disable: 6285) // (<non-zero constant>) || (<non-zero constant>) is always a non-zero constant. Did you intend to use bitwize-and operator?
667  #pragma warning (disable: 6319) // Use of the comma-operator in a tested expression causes the left argument to be ignored when it has no side-effects
668  #pragma warning (disable: 6326) // Potential comparison of a constant with another constant
669  #pragma warning (disable: 6553) // The annotation for function 'func' on _Param_(N) does not apply to a value type.
670  #pragma warning (disable: 26135) // Missing locking annotation
671  #pragma warning (disable: 26400) // Do not assign the result of an allocation or a function call with an owner<T> return value to a raw pointer, use owner<T> instead (i.11).
672  #pragma warning (disable: 26401) // Do not delete a raw pointer that is not an owner<T> (i.11).
673  #pragma warning (disable: 26403) // Reset or explicitly delete an owner<T> pointer 'name' (r.3).
674  #pragma warning (disable: 26408) // Avoid malloc() and free(), prefer the nothrow version of new with delete (r.10).
675  #pragma warning (disable: 26409) // Avoid calling new and delete explicitly, use std::make_unique<T> instead (r.11).
676  #pragma warning (disable: 26426) // Global initializer calls a non-constexpr function 'name' (i.22).
677  #pragma warning (disable: 26429) // Symbol 'name' is never tested for nullness, it can be marked as not_null (f.23).
678  #pragma warning (disable: 26430) // Symbol 'name' is not tested for nullness on all paths (f.23).
679  #pragma warning (disable: 26432) // If you define or delete any default operation in the type 'struct 'name'', define or delete them all (c.21).
680  #pragma warning (disable: 26435) // Function 'name' should specify exactly one of 'virtual', 'override', or 'final' (c.128).
681  #pragma warning (disable: 26438) // Avoid 'goto' (es.76).
682  #pragma warning (disable: 26440) // Function 'name' can be declared 'noexcept' (f.6).
683  #pragma warning (disable: 26446) // Prefer to use gsl::at() instead of unchecked subscript operator (bounds.4).
684  #pragma warning (disable: 26447) // The function is declared 'noexcept' but calls function 'func' which may throw exceptions (f.6).
685  #pragma warning (disable: 26448) // Consider using gsl::finally if final action is intended (gsl.util).
686  #pragma warning (disable: 26451) // Arithmetic overflow: Using operator 'op' on a n-byte value and then casting the result to a m-byte value. Cast the value to the wider type before calling operator 'op' to avoid overflow (io.2).
687  #pragma warning (disable: 26455) // Default constructor may not throw. Declare it 'noexcept' (f.6).
688  #pragma warning (disable: 26457) // (void) should not be used to ignore return values, use 'std::ignore =' instead (es.48)
689  #pragma warning (disable: 26460) // The reference argument 'stream' for function 'name' can be marked as const (con.3).
690  #pragma warning (disable: 26461) // The pointer argument 'name' for function 'name' can be marked as a pointer to const (con.3).
691  #pragma warning (disable: 26462) // The value pointed to by 'name' is assigned only once, mark it as a pointer to const (con.4).
692  #pragma warning (disable: 26482) // Only index into arrays using constant expressions (bounds.2).
693  #pragma warning (disable: 26483) // Value 'value' is outside the bounds (min, max) of variable 'name'. Only index into arrays using constant expressions that are within bounds of the array (bounds.2).
694  #pragma warning (disable: 26485) // Expression 'expr': No array to pointer decay (bounds.3).
695  #pragma warning (disable: 26486) // Don't pass a pointer that may be invalid to a function. Parameter 'n' 'name' in call to 'name' may be invalid (lifetime.3).
696  #pragma warning (disable: 26487) // Don't return a pointer 'name' that may be invalid (lifetime.4).
697  #pragma warning (disable: 26488) // Do not dereference a potentially null pointer: 'name'. 'name' was null at line 'n' (lifetime.1).
698  #pragma warning (disable: 26489) // Don't dereference a pointer that may be invalid: 'name'. 'name' may have been invalidated at line 'n' (lifetime.1).
699  #pragma warning (disable: 26490) // Don't use reinterpret_cast (type.1).
700  #pragma warning (disable: 26492) // Don't use const_cast to cast away const or volatile (type.3).
701  #pragma warning (disable: 26493) // Don't use C-style casts (type.4).
702  #pragma warning (disable: 26496) // The variable 'name' is assigned only once, mark it as const (con.4).
703  #pragma warning (disable: 26497) // The function 'name' could be marked constexpr if compile-time evaluation is desired (f.4).
704  #pragma warning (disable: 26812) // The enum type 'type' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
705  #pragma warning (disable: 26814) // The const variable 'name' can be computed at compile-time. Consider using constexpr (con.5).
706  #pragma warning (disable: 26822) // Dereferencing a possibly null pointer '...' (lifetime.1).
707  #pragma warning (disable: 26823) // Dereferencing a possibly null pointer '...' (lifetime.1).
708  #pragma warning (disable: 28125) // The function must be called from within a try/except block
709  #pragma warning (disable: 28159) // Consider using another function instead
710 
711  #pragma warning (default: 4616) // #pragma warning: warning number 'n' not a valid compiler warning //-V665
712 
713  #define _tx_thread __declspec (thread)
714  #define _tx_decltype(value) decltype (value)
715 
716  #if !defined (_CLANG_VER)
717 
718  #pragma setlocale ("russian") // Set source file encoding, see also _TX_CODEPAGE
719 
720  #if !defined (NDEBUG)
721  #pragma check_stack ( on) // Turn on stack probes at runtime
722  #pragma strict_gs_check (push, on) // Detects stack buffer overruns
723  #endif
724 
725  #endif
726 
727  #define _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 1
728 
729 #endif
730 
731 //-----------------------------------------------------------------------------------------------------------------
732 
733 #if defined (__INTEL_COMPILER)
734 
735  #pragma warning (disable: 174) // Remark: expression has no effect
736  #pragma warning (disable: 304) // Remark: access control not specified ("public" by default)
737  #pragma warning (disable: 444) // Remark: destructor for base class "..." is not virtual
738  #pragma warning (disable: 522) // Remark: function "..." redeclared "inline" after being called
739  #pragma warning (disable: 981) // Remark: operands are evaluated in unspecified order
740  #pragma warning (disable: 1684) // Conversion from pointer to same-sized integral type (potential portability problem)
741 
742 #endif
743 
744 //-----------------------------------------------------------------------------------------------------------------
745 
746 #if (defined (_GCC_VER) && (_GCC_VER < 472) || \
747  defined (_MSC_VER) && (_MSC_VER < 1600)) // Minimum requirements are now GCC 4.7.2 or MSVC 10.0 (2010)
748 
749  #ifdef __GNUC__
750  #error
751  #error ---------------------------------------------------------------------------------------
752  #endif
753  #error TXLib.h: This version will NOT work with GCC < 4.7.2 or MS Visual Studio < 2010, sorry.
754  #error
755  #error Please use TXLib.h previous stable version/revision OR upgrade your compiler.
756  #error ---------------------------------------------------------------------------------------
757  #error
758 
759 #endif
760 
761 //-----------------------------------------------------------------------------------------------------------------
762 
763 #if defined (_GCC_VER) && (_GCC_VER >= 492)
764 #if defined (TX_USE_SPEAK) && !__has_include (<SAPI.h>)
765 
766  #ifdef __GNUC__
767  #error
768  #error ---------------------------------------------------------------------------------------
769  #endif
770  #error You have defined TX_USE_SPEAK, but your compiler do NOT have the library <SAPI.h>.
771  #error
772  #error Please use compiler library set with SAPI.h included. SAPI is Microsoft Speech API
773  #error nesessary for txSpeak() to work.
774  #error ---------------------------------------------------------------------------------------
775  #error
776 
777 #endif
778 #endif
779 
780 //-----------------------------------------------------------------------------------------------------------------
781 
782 #if !defined (WINVER)
783  #define WINVER 0x0500 // Defaults to Windows 2000
784  #define WINDOWS_ENABLE_CPLUSPLUS // Allow use of type-limit macros in <basetsd.h>,
785 #endif // they are allowed by default if WINVER >= 0x0600.
786 
787 #if !defined (_WIN32_WINNT)
788  #define _WIN32_WINNT WINVER // Defaults to the same as WINVER
789 #endif
790 
791 #if !defined (_WIN32_IE)
792  #define _WIN32_IE WINVER // Defaults to the same as WINVER
793 #endif
794 
795 #define stristr( str1, str2 ) Win32::StrStrIA ((str1), (str2))
796 #define stristrw( str1, str2 ) Win32::StrStrIW ((str1), (str2))
797 
798 //-----------------------------------------------------------------------------------------------------------------
799 
800 #define _USE_MATH_DEFINES 1 // Math.h's M_PI etc.
801 #define __STDC_FORMAT_MACROS 1 // PRIu64 and other PR... macros
802 #define __STDC_WANT_LIB_EXT1__ 1 // String and output *_s functions
803 
804 #define _LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS // Wow, how long. Kudos, Clang
805 
806 #define _ALLOW_RTCc_IN_STL 1 // MSVC C2338: /RTCc rejects conformant code, so it isn't supported by libc.
807 
808 #define NOMINMAX 1 // Preventing 'min' and 'max' defines in Windows.h
809 
810 #if defined (_DEBUG)
811 #define _SECURE_SCL 1 // Enable checked STL iterators to throw an exception on incorrect use
812 #define _HAS_ITERATOR_DEBUGGING 1
813 #define _LIBCPP_DEBUG 1
814 #endif
815 
816 #if defined (_MSC_VER) && defined (_DEBUG)
817 
818  #define _CRTDBG_MAP_ALLOC // Enable MSVCRT debug heap
819  #define _new_dbg new (_NORMAL_BLOCK, __FILE__, __LINE__)
820  #define NEW new (_NORMAL_BLOCK, __FILE__, __LINE__)
821 
822 #else
823  #define _new_dbg new
824  #define NEW new
825 
826 #endif
827 
828 #if !( defined (_MSC_VER) && (_MSC_VER < 1900) ) // MSVC 2015
829 #define _SECURE_SCL_THROWS 1
830 #endif
831 
832 #define tx_noreturn __attribute__ (( noreturn ))
833 #define tx_nodiscard __attribute__ (( warn_unused_result ))
834 #define tx_deprecated __attribute__ (( deprecated ))
835 #define tx_printfy( formatArgN ) __attribute__ (( format (printf, (formatArgN), (formatArgN)+1) ))
836 #define tx_scanfy( formatArgN ) __attribute__ (( format (scanf, (formatArgN), (formatArgN)+1) ))
837 
838 
839 #if defined (_TX_CPP11)
840 
841  #define _tx_delete = delete
842  #define _tx_default = default
843  #define _tx_override override
844  #define _tx_final final
845 
846 #else
847 
848  #define _tx_delete
849  #define _tx_default
850  #define _tx_override
851  #define _tx_final
852 
853 #endif
854 
855 namespace std { enum nomeow_t { nomeow }; } // Vital addition to the C++ standard. TODO: Should contact C++ std committee.
856 
857 //-----------------------------------------------------------------------------------------------------------------
858 
860 //}
861 //-----------------------------------------------------------------------------------------------------------------
862 
863 //-----------------------------------------------------------------------------------------------------------------
864 //{ The Includes
865 //-----------------------------------------------------------------------------------------------------------------
866 
867 #if defined (_MSC_VER)
868  #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o
869 
870  #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch
871  #pragma warning (disable: 4005) // 'name': macro redefinition
872 #endif
873 
874 //-----------------------------------------------------------------------------------------------------------------
875 
876 #include <stdlib.h>
877 #include <stdio.h>
878 #include <string.h>
879 #include <time.h>
880 #include <math.h>
881 #include <float.h>
882 
883 #include <vector>
884 #include <string>
885 #include <iostream>
886 #include <sstream>
887 #include <iomanip>
888 
889 #if !defined (__CYGWIN__)
890 #include <conio.h>
891 #include <direct.h>
892 #endif
893 
894 #if defined (TX_COMPILED)
895 #define WIN32_LEAN_AND_MEAN
896 #endif
897 
898 #include <windows.h>
899 #include <mmsystem.h>
900 
901 //-----------------------------------------------------------------------------------------------------------------
902 //{ Compiler- and platform-specific
904 //-----------------------------------------------------------------------------------------------------------------
905 
906 #if defined (_MSC_VER)
907  #pragma warning (pop) // MSVC: Restore max level
908 #endif
909 
910 #if defined (__STRICT_ANSI__UNDEFINED)
911  #define __STRICT_ANSI__ // Redefine back
912 #endif
913 
914 #if !defined (_TRUNCATE) || defined (__CYGWIN__) || defined (_MEMORY_S_DEFINED)
915 
916  #define strncpy_s( dest, sizeof_dest, src, count ) ( strncpy ((dest), (src), MIN ((count), (sizeof_dest))) )
917  #define wcsncpy_s( dest, sizeof_dest, src, count ) ( wcsncpy ((dest), (src), MIN ((count), (sizeof_dest))) )
918  #define strncat_s( dest, sizeof_dest, src, count ) ( strncat ((dest), (src), MIN ((count), (sizeof_dest))) )
919  #define strerror_s( buf, sizeof_buf, code ) ( strncpy ((buf), strerror ((int)(code)), (sizeof_buf)-1) )
920  #define strtok_s( buf, delim, ctx ) ( (void)(ctx), strtok ((buf), (delim)) )
921  #define fopen_s( file, name, mode ) ( *(file) = fopen ((name), (mode)) )
922  #define _strlwr_s( str, sizeof_str ) ( _strlwr (str) )
923 
924  #define ctime_s( buf, sizeof_buf, time ) ( strncpy ((buf), ctime (time), (sizeof_buf)-1) )
925  #define _controlfp_s( oldCtl, newCtl, mask ) ( assert (oldCtl), *(oldCtl) = _controlfp (newCtl, mask), 0 )
926 
927  #define _snprintf_s snprintf
928  #define _vsnprintf_s( str, sz, trunc, format, arg ) _vsnprintf (str, sz, format, arg)
929 
930 #endif
931 
932 #if !( defined (_MSC_VER) || defined (__STDC_LIB_EXT1__) )
933 
934  #define getenv_s( sz, buf, sizeof_buf, name ) ( (void)(sz), strncpy ((buf), getenv (name), (sizeof_buf)-1) )
935 
936 #endif
937 
938 #if defined (__CYGWIN__)
939 
940  #undef __STRICT_ANSI__
941 
942  typedef void _exception;
943 
944  #define _O_TEXT O_TEXT
945  #define _fdopen fdopen
946  #define _flushall() fflush (NULL)
947  #define _getcwd getcwd
948  #define _getpid getpid
949  #define _stricmp strcasecmp
950  #define _strlwr strlwr
951  #define _strnicmp strncasecmp
952  #define _unlink unlink
953  #define _vsnprintf vsnprintf
954  #define _access access
955  #define _strdup strdup
956 
957  #define getch _getch
958  #define putch _putch
959  #define kbhit _kbhit
960 
961 #endif
962 
963 #if !defined (PRId64) || \
964  defined (_GCC_VER) && (_GCC_VER == 492) && !defined (_WIN64) // Dev-CPP 5.11: TDM-GCC 4.9.2 MinGW64 with -m32
965 
966  #undef PRId64
967  #undef PRIi64
968  #undef PRIo64
969  #undef PRIu64
970  #undef PRIx64
971  #undef PRIX64
972 
973  #define PRId64 "I64d"
974  #define PRIi64 "I64i"
975  #define PRIo64 "I64o"
976  #define PRIu64 "I64u"
977  #define PRIx64 "I64x"
978  #define PRIX64 "I64X"
979 
980 #endif
981 
982 //}
983 //-----------------------------------------------------------------------------------------------------------------
984 
985 //}
986 //-----------------------------------------------------------------------------------------------------------------
987 
988 //-----------------------------------------------------------------------------------------------------------------
989 //{ The namespaces
990 //-----------------------------------------------------------------------------------------------------------------
991 
992 //{----------------------------------------------------------------------------------------------------------------
995 //}----------------------------------------------------------------------------------------------------------------
996 
997 #ifdef FOR_DOXYGEN_ONLY
998 namespace { namespace TX { }}
999 #endif
1000 
1003 //-----------------------------------------------------------------------------------------------------------------
1004 
1005 #if defined (TX_COMPILED) && defined (TX_COMPILING)
1006  #undef TX_COMPILED
1007  #endif
1008 
1009 #if !defined (TX_COMPILED) && !defined (TX_COMPILING)
1010 
1011  #define _TX_BEGIN_NAMESPACE namespace { namespace TX {
1012  #define _TX_END_NAMESPACE } }
1013 
1014 #else
1015 
1016  #define _TX_BEGIN_NAMESPACE namespace TX {
1017  #define _TX_END_NAMESPACE }
1018 
1019 #endif
1020 
1021 //-----------------------------------------------------------------------------------------------------------------
1022 
1023 _TX_BEGIN_NAMESPACE
1024 
1027 //}
1028 //-----------------------------------------------------------------------------------------------------------------
1029 
1030 //=================================================================================================================
1031 //{ TXLIB INTERFACE
1032 // Интерфейс библиотеки
1033 //=================================================================================================================
1034 
1035 //=================================================================================================================
1036 //{ Initialization
1038 //=================================================================================================================
1040 //{----------------------------------------------------------------------------------------------------------------
1084 //}----------------------------------------------------------------------------------------------------------------
1085 
1086 HWND txCreateWindow (double sizeX, double sizeY, bool centered = true);
1087 
1088 //{----------------------------------------------------------------------------------------------------------------
1115 //}----------------------------------------------------------------------------------------------------------------
1116 
1117 inline HDC& txDC() tx_nodiscard;
1118 
1119 //{----------------------------------------------------------------------------------------------------------------
1155 //}----------------------------------------------------------------------------------------------------------------
1156 
1157 inline RGBQUAD* txVideoMemory() tx_nodiscard;
1158 
1159 //{----------------------------------------------------------------------------------------------------------------
1178 //}----------------------------------------------------------------------------------------------------------------
1179 
1180 bool txSetDefaults (HDC dc = txDC());
1181 
1182 //{----------------------------------------------------------------------------------------------------------------
1201 //}----------------------------------------------------------------------------------------------------------------
1202 
1203 inline bool txOK() tx_nodiscard;
1204 
1205 //{----------------------------------------------------------------------------------------------------------------
1237 //}----------------------------------------------------------------------------------------------------------------
1238 
1239 POINT txGetExtent (HDC dc = txDC()) tx_nodiscard;
1240 
1241 //{----------------------------------------------------------------------------------------------------------------
1258 //}----------------------------------------------------------------------------------------------------------------
1259 
1260 inline int txGetExtentX (HDC dc = txDC()) tx_nodiscard;
1261 
1262 //{----------------------------------------------------------------------------------------------------------------
1280 //}----------------------------------------------------------------------------------------------------------------
1281 
1282 inline int txGetExtentY (HDC dc = txDC()) tx_nodiscard;
1283 
1284 //{----------------------------------------------------------------------------------------------------------------
1296 //}----------------------------------------------------------------------------------------------------------------
1297 
1298 inline HWND txWindow() tx_nodiscard;
1299 
1300 //{----------------------------------------------------------------------------------------------------------------
1309 //}----------------------------------------------------------------------------------------------------------------
1310 
1311 inline const char* txVersion() tx_nodiscard;
1312 
1313 //{----------------------------------------------------------------------------------------------------------------
1322 //}----------------------------------------------------------------------------------------------------------------
1323 
1324 inline unsigned txVersionNumber() tx_nodiscard;
1325 
1326 //{----------------------------------------------------------------------------------------------------------------
1356 //}----------------------------------------------------------------------------------------------------------------
1357 
1358 const char* txGetModuleFileName (bool fileNameOnly = true) tx_nodiscard;
1359 
1361 //{----------------------------------------------------------------------------------------------------------------
1396 //}----------------------------------------------------------------------------------------------------------------
1397 
1398 int txMessageBox (const char text[] = "Муаххаха! :)", const char header[] = "TXLib сообщает",
1399  unsigned flags = MB_ICONINFORMATION | MB_OKCANCEL);
1400 
1401 //{----------------------------------------------------------------------------------------------------------------
1418 //}----------------------------------------------------------------------------------------------------------------
1419 
1420 HRESULT txSetProgress (double percent, unsigned type = 2 /*TBPF_NORMAL*/, HWND wnd = NULL);
1421 
1422 //}
1423 //=================================================================================================================
1424 
1425 //=================================================================================================================
1426 //{ Setting the parameters
1428 //=================================================================================================================
1430 //{----------------------------------------------------------------------------------------------------------------
1456 //}----------------------------------------------------------------------------------------------------------------
1457 
1458 const COLORREF
1459 #ifdef FOR_DOXYGEN_ONLY
1460  enum txColors {
1461 #endif
1462 
1463  TX_BLACK = RGB ( 0, 0, 0),
1464  TX_BLUE = RGB ( 0, 0, 128),
1465  TX_GREEN = RGB ( 0, 128, 0),
1466  TX_CYAN = RGB ( 0, 128, 128),
1467  TX_RED = RGB (128, 0, 0),
1468  TX_MAGENTA = RGB (128, 0, 128),
1469  TX_BROWN = RGB (128, 128, 0),
1470  TX_ORANGE = RGB (255, 128, 0),
1471  TX_GRAY = RGB (160, 160, 160),
1472  TX_DARKGRAY = RGB (128, 128, 128),
1473  TX_LIGHTGRAY = RGB (192, 192, 192),
1474  TX_LIGHTBLUE = RGB ( 0, 0, 255),
1475  TX_LIGHTGREEN = RGB ( 0, 255, 128),
1476  TX_LIGHTCYAN = RGB ( 0, 255, 255),
1477  TX_LIGHTRED = RGB (255, 0, 128),
1478  TX_LIGHTMAGENTA = RGB (255, 0, 255),
1479  TX_PINK = RGB (255, 128, 255),
1480  TX_YELLOW = RGB (255, 255, 128),
1481  TX_WHITE = RGB (255, 255, 255),
1482  TX_TRANSPARENT = 0xFFFFFFFF,
1486 
1487 // Цветовые каналы (компоненты) -- см. txExtractColor(), txRGB2HSL(), txHSL2RGB()
1488 
1489  TX_HUE = 0x04000000,
1490  TX_SATURATION = 0x05000000,
1491  TX_LIGHTNESS = 0x06000000;
1492 
1493 #ifdef FOR_DOXYGEN_ONLY
1494  };
1495 #endif
1496 
1498 #define TX_GREY TX_GRAY
1499 #define TX_DARKGREY TX_DARKGRAY
1500 #define TX_LIGHTGREY TX_LIGHTGRAY
1502 
1503 //{----------------------------------------------------------------------------------------------------------------
1528 //}----------------------------------------------------------------------------------------------------------------
1529 
1530 #ifdef FOR_DOXYGEN_ONLY
1531 COLORREF RGB (int red, int green, int blue);
1532 #endif
1533 
1534 //{----------------------------------------------------------------------------------------------------------------
1553 //}----------------------------------------------------------------------------------------------------------------
1554 
1555 HPEN txSetColor (COLORREF color, double thickness = 1, HDC dc = txDC());
1556 
1558 #define txSetColour txSetColor
1560 
1562 
1563 //{----------------------------------------------------------------------------------------------------------------
1574 //}----------------------------------------------------------------------------------------------------------------
1575 
1576 COLORREF txColor (double red, double green, double blue);
1577 
1579 
1580 //{----------------------------------------------------------------------------------------------------------------
1593 //}----------------------------------------------------------------------------------------------------------------
1594 
1595 COLORREF txGetColor (HDC dc = txDC()) tx_nodiscard;
1596 
1597 //{----------------------------------------------------------------------------------------------------------------
1612 //}----------------------------------------------------------------------------------------------------------------
1613 
1614 HBRUSH txSetFillColor (COLORREF color, HDC dc = txDC());
1615 
1617 #define txSetFillColour txSetFillColor
1619 
1621 
1622 //{----------------------------------------------------------------------------------------------------------------
1633 //}----------------------------------------------------------------------------------------------------------------
1634 
1635 COLORREF txFillColor (double red, double green, double blue);
1636 
1638 
1639 //{----------------------------------------------------------------------------------------------------------------
1652 //}----------------------------------------------------------------------------------------------------------------
1653 
1654 COLORREF txGetFillColor (HDC dc = txDC()) tx_nodiscard;
1655 
1656 //{----------------------------------------------------------------------------------------------------------------
1674 //}----------------------------------------------------------------------------------------------------------------
1675 
1676 unsigned txExtractColor (COLORREF color, COLORREF component) tx_nodiscard;
1677 
1678 //{----------------------------------------------------------------------------------------------------------------
1706 //}----------------------------------------------------------------------------------------------------------------
1707 
1708 COLORREF txRGB2HSL (COLORREF rgbColor) tx_nodiscard;
1709 
1710 //{----------------------------------------------------------------------------------------------------------------
1740 //}----------------------------------------------------------------------------------------------------------------
1741 
1742 COLORREF txHSL2RGB (COLORREF hslColor) tx_nodiscard;
1743 
1745 //}
1746 //=================================================================================================================
1747 
1748 //=================================================================================================================
1749 //{ Drawing
1751 //=================================================================================================================
1753 //{----------------------------------------------------------------------------------------------------------------
1767 //}----------------------------------------------------------------------------------------------------------------
1768 
1769 bool txClear (HDC dc = txDC());
1770 
1771 //{----------------------------------------------------------------------------------------------------------------
1789 //}----------------------------------------------------------------------------------------------------------------
1790 
1791 inline bool txSetPixel (double x, double y, COLORREF color, HDC dc = txDC());
1792 
1794 
1795 //{----------------------------------------------------------------------------------------------------------------
1813 //}----------------------------------------------------------------------------------------------------------------
1814 
1815 inline bool txPixel (double x, double y, double red, double green, double blue, HDC dc = txDC());
1816 
1818 
1819 //{----------------------------------------------------------------------------------------------------------------
1837 //}----------------------------------------------------------------------------------------------------------------
1838 
1839 inline COLORREF txGetPixel (double x, double y, HDC dc = txDC()) tx_nodiscard;
1840 
1841 //{----------------------------------------------------------------------------------------------------------------
1861 //}----------------------------------------------------------------------------------------------------------------
1862 
1863 bool txLine (double x0, double y0, double x1, double y1, HDC dc = txDC());
1864 
1865 //{----------------------------------------------------------------------------------------------------------------
1887 //}----------------------------------------------------------------------------------------------------------------
1888 
1889 bool txRectangle (double x0, double y0, double x1, double y1, HDC dc = txDC());
1890 
1891 //{----------------------------------------------------------------------------------------------------------------
1911 //}----------------------------------------------------------------------------------------------------------------
1912 
1913 bool txPolygon (const POINT points[], int numPoints, HDC dc = txDC());
1914 
1915 //{----------------------------------------------------------------------------------------------------------------
1935 //}----------------------------------------------------------------------------------------------------------------
1936 
1937 bool txEllipse (double x0, double y0, double x1, double y1, HDC dc = txDC());
1938 
1939 //{----------------------------------------------------------------------------------------------------------------
1957 //}----------------------------------------------------------------------------------------------------------------
1958 
1959 bool txCircle (double x, double y, double r);
1960 
1961 //{----------------------------------------------------------------------------------------------------------------
1984 //}----------------------------------------------------------------------------------------------------------------
1985 
1986 bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc = txDC());
1987 
1988 //{----------------------------------------------------------------------------------------------------------------
2011 //}----------------------------------------------------------------------------------------------------------------
2012 
2013 bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc = txDC());
2014 
2015 //{----------------------------------------------------------------------------------------------------------------
2038 //}----------------------------------------------------------------------------------------------------------------
2039 
2040 bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc = txDC());
2041 
2042 //{----------------------------------------------------------------------------------------------------------------
2074 //}----------------------------------------------------------------------------------------------------------------
2075 
2076 bool txFloodFill (double x, double y, COLORREF color = TX_TRANSPARENT, DWORD mode = FLOODFILLSURFACE, HDC dc = txDC());
2077 
2078 //{----------------------------------------------------------------------------------------------------------------
2096 //}----------------------------------------------------------------------------------------------------------------
2097 
2098 inline bool txTriangle (double x1, double y1, double x2, double y2, double x3, double y3)
2099  {
2100  (void)x1; (void)y1; (void)x2; (void)y2; (void)x3; (void)y3;
2101 
2102  txMessageBox ("txTriangle (double x1, double y1, double x2, double y2, double x3, double y3)\n\n"
2103  "Эта функция не реализована в библиотеке, потому что вы легко можете реализовать ее сами "
2104  "как функцию с параметрами, используя txPolygon(). См. \"Пример с функциями с параметрами". " "Ну или нарисовать тремя линиями. :)", "TXLib сообщает"); return false; } //{---------------------------------------------------------------------------------------------------------------- //! @cond INTERNAL bool txNotifyIcon (unsigned flags, const char title[], const char format[], ...) tx_printfy (3); #define txRectandle Sleep (1000), txRectangle // Copy-protection for the function below #define txLine(...) txLine (__VA_ARGS__); { // #define txNotifyIcon }}}}}}}}}} txNotifyIcon // Не спрашивайте, зачем. Это дичь. #define txCircle ;txCircle // #define txSetColor ;txSetColor // #define C0L0RREF COLORREF // #define OxFFFFFF 0xFFFFFF // #define lO 10 // #define lOOO 1000 // #define oo // #define O // //! @endcond //} //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Drawing //! @brief Рисует человечка. //! //! Это пример функции, которую Вы могли бы написать и сами. //! //! @param x X-координата человечка. //! @param y Y-координата человечка. //! @param sizeX Ширина человечка. //! @param sizeY Высота человечка (также определяет размер головы). //! @param color Цвет человечка. //! @param handL Высота подъема левой руки (относительно высоты человечка). //! @param handR Высота подъема правой руки (относительно высоты человечка). //! @param twist Смещение @a спины (относительно ширины человечка). //! @param head Высота @a подъема головы (относительно высоты человечка). //! @param eyes Величина глаз (относительно размера головы). //! @param wink Моргание глаз (0 -- оба открыты, -1 -- закрыт левый, +1 -- закрыт правый). //! @param crazy Смещение глаз по вертикали (относительно размера головы). //! @param smile Улыбка (относительно размера головы). //! @param hair Длина волос (относительно размера головы). //! @param wind Ветер, развевающий волосы (относительно размера головы). //! //! @see txSetFillColor(), txColors, RGB(), txLine(), txCircle() //! //! @usage @code //! txCreateWindow (800, 600); //! //! //-----------+---+----+-----+-----+----------+-----+-----+-----+----+----+----+-----+-----+----+----- //! // | x | y |sizeX|sizeY| color |handL|handR|twist|head|eyes|wink|crazy|smile|hair|wind //! //-----------+---+----+-----+-----+----------+-----+-----+-----+----+----+----+-----+-----+----+----- //! // | | | | | | | | | | | | | | | //! txDrawMan (125, 250, 200, 200, TX_WHITE, 0, 0, 0, 0, 0.8, 0, 0, 1.0, 0, 0); //! txDrawMan (325, 250, 100, 200, TX_YELLOW, 0, 0, 0, 0, 0.8, 0, 0, -1.0, 2, 0); //! txDrawMan (525, 250, 200, 100, TX_ORANGE, 0, 0, 0, 0, 1.0, 0, -1, 0.3, 1, 0); //! txDrawMan (725, 250, 100, 100, TX_LIGHTRED, 0, 0, 0, 0, 1.0, 0, 1, -0.3, 3, 0); //! //! txDrawMan (125, 550, 200, 200, TX_WHITE, 0.3, 0.3, 0, 0, 0.8, -1, 1, 0.5, 2, -1); //! txDrawMan (325, 550, 100, 200, TX_YELLOW, -0.5, -0.5, 0, 0.1, 0.8, 1, 0, -0.5, 3, 5); //! txDrawMan (525, 550, 200, 100, TX_ORANGE, -0.5, 0.3, 0.2, 0, 0.8, -1, 1, 0.0, 10, -5); //! txDrawMan (725, 550, 100, 100, TX_LIGHTRED, 0.3, -0.5, -0.4, 0, 0.8, 1, -1, 0.0, 1, 1); //! @endcode //}----------------------------------------------------------------------------------------------------------------////// // inline void txDrawMan (int x, int y, int sizeX, int sizeY, COLORREF color, double handL, double handR, double twist, // double head, double eyes, double wink, double crazy, double smile, double hair, double wind) // { // const char __[] = "\0/А я - человечек из библиотеки!\0/Меня объясняли на уроке!\0/Напиши меня сам!\0/"; // // | | | | // // Не копипастите! _/ \_ Все равно не получится! :) _/ \_ Человечки защищают _/ \_ этот код! :) _/ \_ Муаххаха! // // // static int count = GetTickCount(), L = 0; ////////////////////////////////////////////////////////////////////////// C0L0RREF lineColor = txGetColor(); C0L0RREF fillColor = txGetFillColor(); txSetColor (color, 3); txSetFillColor (color); txLine (x + twist * sizeX, y - O.35 * sizeY, x, y - O.7 * sizeY); txLine (x, y - O.7 * sizeY, x - sizeX/2.0, y - (O.7 + handL) * sizeY); txLine (x, y - O.7 * sizeY, x + sizeX/2.0, y - (O.7 + handR) * sizeY); txLine (x + twist * sizeX, y - O.35 * sizeY, x - sizeX/2.0, y); txLine (x + twist * sizeX, y - O.35 * sizeY, x + sizeX/2.0, y); txCircle (x, y - (O.85 + head) * sizeY, O.15 * sizeY); txLine (x, y - (1 + head) * sizeY, x + wind/lO * sizeX, y - (1 + head + hair/lO) * sizeY); txLine (x, y - (1 + head) * sizeY, x + (wind/lO - O.1) * sizeX, y - (1 + head + hair/lO) * sizeY); txLine (x, y - (1 + head) * sizeY, x + (wind/lO + O.1) * sizeX, y - (1 + head + hair/lO) * sizeY); txSetColor (~color & OxFFFFFF); // Inverse the color txSetFillColor (~color & OxFFFFFF); txLine (x, y - (O.8 + head - O.05 * smile/2) * sizeY, x - O.05 * sizeY, y - (O.8 + head + O.05 * smile/2) * sizeY); txLine (x, y - (O.8 + head - O.05 * smile/2) * sizeY, x + O.05 * sizeY, y - (O.8 + head + O.05 * smile/2) * sizeY); oo txNotifyIcon (4, (const char*)!! (L+'L')[(__)], "\n%s\n", __ + ((unsigned) (((count -=- 1) ^=! 1) ^=~ ((0)^(0)) +1) % 3)["\x02\"<"]); //-V112 //-V542 oo // See above: Frog construct [(__)], Mouth operator -=-, Cat operator ^=!, Mouse operator ^=~ and Owl constant ((0)^(0)). Use it freely, meow txCircle (x - O.05 * sizeY, y - (O.9 + head - O.02 * crazy) * sizeY, eyes * (1 + O.5*wink) * O.02 * sizeY); txCircle (x + O.05 * sizeY, y - (O.9 + head + O.02 * crazy) * sizeY, eyes * (1 - O.5*wink) * O.02 * sizeY); Sleep (lOOO + count%2); txSetColor ((color == 0xDEADFACE)? TX_DARKGRAY : TX_TRANSPARENT); txSetFillColor (TX_TRANSPARENT); txCircle (x, y, 4); //-V112 txRectandle (x - sizeX/2.0, y - sizeY, x + sizeX/2.0, y); txSetColor (lineColor); txSetFillColor (fillColor); } //! @} //} //================================================================================================================= //================================================================================================================= //{ Drawing text //! @name Работа с текстом //================================================================================================================= //! @{ //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Drawing //! @brief Рисует текст. //! //! @param x X-координата начальной точки текста. //! @param y Y-координата начальной точки текста. //! @param text Текстовая строка. //! @param dc <i>Дескриптор контекста рисования (холста) для рисования. Необязателен.</i> //! //! @return Если операция была успешна -- true, иначе -- false. //! //! Цвет текста задается функцией txSetColor(), выравнивание (влево/вправо/по центру) -- txSetTextAlign(). //! //! @see txSetColor(), txGetColor(), txSetFillColor(), txGetFillColor(), txColors, RGB(), //! txSelectFont(), txSetTextAlign(), txGetTextExtent(), txGetTextExtentX(), txGetTextExtentY() //! //! @usage @code //! txTextOut (100, 100, "Здесь могла бы быть Ваша реклама."); //! @endcode //}---------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc = txDC()); //{---------------------------------------------------------------------------------------------------------------- //! @cond INTERNAL #undef txRectandle #undef txLine #undef txNotifyIcon #undef txCircle #undef txSetColor #undef C0L0RREF #undef OxFFFFFF #undef lO #undef lOOO #undef oo #undef O //! @endcond //} //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Drawing //! @brief Рисует текст, размещенный в прямоугольной области. //! //! @param x0 X-координата верхнего левого угла области. //! @param y0 Y-координата верхнего левого угла области. //! @param x1 X-координата нижнего правого угла области. //! @param y1 Y-координата нижнего правого угла области. //! @param text Текстовая строка. //! @param format <i>Флаги форматирования текста. Необязательны. Если не указаны, то используется: центрирование, //! перенос по словам и добавление многоточия, если надпись не умещается в область.</i> //! @param dc <i>Дескриптор контекста рисования (холста) для рисования. Необязателен.</i> //! //! @return Если операция была успешна -- true, иначе -- false. //! //! Цвет текста задается функцией txSetColor(), выравнивание (влево/вправо/по центру) -- txSetTextAlign(). //! //! @note Не выводит ничего, если координаты идут в неверном порядке (если x0 > x1 или y0 > y1). //! //! Флаги форматирования текста см. в MSDN (http://msdn.com), искать "DrawText Function (Windows)": //! http://msdn.microsoft.com/en-us/library/dd162498%28VS.85%29.aspx. //! //! <b>Автоматический перенос
2105  "Ну или нарисовать тремя линиями. :)", "TXLib сообщает");
2106  return false;
2107  }
2108 
2109 //{----------------------------------------------------------------------------------------------------------------
2111 
2112 bool txNotifyIcon (unsigned flags, const char title[], const char format[], ...) tx_printfy (3);
2113 
2114 #define txRectandle Sleep (1000), txRectangle // Copy-protection for the function below
2115 #define txLine(...) txLine (__VA_ARGS__); { //
2116 #define txNotifyIcon }}}}}}}}}} txNotifyIcon // Не спрашивайте, зачем. Это дичь.
2117 #define txCircle ;txCircle //
2118 #define txSetColor ;txSetColor //
2119 #define C0L0RREF COLORREF //
2120 #define OxFFFFFF 0xFFFFFF //
2121 #define lO 10 //
2122 #define lOOO 1000 //
2123 #define oo //
2124 #define O //
2125 
2127 //}
2128 
2129 //{----------------------------------------------------------------------------------------------------------------
2170 //}----------------------------------------------------------------------------------------------------------------//////
2171  //
2172 inline void txDrawMan (int x, int y, int sizeX, int sizeY, COLORREF color, double handL, double handR, double twist, //
2173  double head, double eyes, double wink, double crazy, double smile, double hair, double wind) //
2174  { //
2175  const char __[] = "\0/А я - человечек из библиотеки!\0/Меня объясняли на уроке!\0/Напиши меня сам!\0/"; //
2176  // | | | | //
2177  // Не копипастите! _/ \_ Все равно не получится! :) _/ \_ Человечки защищают _/ \_ этот код! :) _/ \_ Муаххаха! //
2178  // //
2179  static int count = GetTickCount(), L = 0;
2180 
2181  C0L0RREF lineColor = txGetColor();
2182  C0L0RREF fillColor = txGetFillColor();
2183 
2184  txSetColor (color, 3);
2185  txSetFillColor (color);
2186 
2187  txLine (x + twist * sizeX, y - O.35 * sizeY, x, y - O.7 * sizeY);
2188 
2189  txLine (x, y - O.7 * sizeY, x - sizeX/2.0, y - (O.7 + handL) * sizeY);
2190  txLine (x, y - O.7 * sizeY, x + sizeX/2.0, y - (O.7 + handR) * sizeY);
2191 
2192  txLine (x + twist * sizeX, y - O.35 * sizeY, x - sizeX/2.0, y);
2193  txLine (x + twist * sizeX, y - O.35 * sizeY, x + sizeX/2.0, y);
2194 
2195  txCircle (x, y - (O.85 + head) * sizeY, O.15 * sizeY);
2196 
2197  txLine (x, y - (1 + head) * sizeY, x + wind/lO * sizeX, y - (1 + head + hair/lO) * sizeY);
2198  txLine (x, y - (1 + head) * sizeY, x + (wind/lO - O.1) * sizeX, y - (1 + head + hair/lO) * sizeY);
2199  txLine (x, y - (1 + head) * sizeY, x + (wind/lO + O.1) * sizeX, y - (1 + head + hair/lO) * sizeY);
2200 
2201  txSetColor (~color & OxFFFFFF); // Inverse the color
2202  txSetFillColor (~color & OxFFFFFF);
2203 
2204  txLine (x, y - (O.8 + head - O.05 * smile/2) * sizeY, x - O.05 * sizeY, y - (O.8 + head + O.05 * smile/2) * sizeY);
2205  txLine (x, y - (O.8 + head - O.05 * smile/2) * sizeY, x + O.05 * sizeY, y - (O.8 + head + O.05 * smile/2) * sizeY);
2206  oo
2207  txNotifyIcon (4, (const char*)!! (L+'L')[(__)], "\n%s\n", __ + ((unsigned) (((count -=- 1) ^=! 1) ^=~ ((0)^(0)) +1) % 3)["\x02\"<"]); //-V112 //-V542
2208  oo
2209  // See above: Frog construct [(__)], Mouth operator -=-, Cat operator ^=!, Mouse operator ^=~ and Owl constant ((0)^(0)). Use it freely, meow
2210 
2211  txCircle (x - O.05 * sizeY, y - (O.9 + head - O.02 * crazy) * sizeY, eyes * (1 + O.5*wink) * O.02 * sizeY);
2212  txCircle (x + O.05 * sizeY, y - (O.9 + head + O.02 * crazy) * sizeY, eyes * (1 - O.5*wink) * O.02 * sizeY);
2213  Sleep (lOOO + count%2);
2214 
2215  txSetColor ((color == 0xDEADFACE)? TX_DARKGRAY : TX_TRANSPARENT);
2217 
2218  txCircle (x, y, 4); //-V112
2219  txRectandle (x - sizeX/2.0, y - sizeY, x + sizeX/2.0, y);
2220 
2221  txSetColor (lineColor);
2222  txSetFillColor (fillColor);
2223  }
2224 
2226 //}
2227 //=================================================================================================================
2228 
2229 //=================================================================================================================
2230 //{ Drawing text
2232 //=================================================================================================================
2234 //{----------------------------------------------------------------------------------------------------------------
2253 //}----------------------------------------------------------------------------------------------------------------
2254 
2255 bool txTextOut (double x, double y, const char text[], HDC dc = txDC());
2256 
2257 //{----------------------------------------------------------------------------------------------------------------
2259 
2260 #undef txRectandle
2261 #undef txLine
2262 #undef txNotifyIcon
2263 #undef txCircle
2264 #undef txSetColor
2265 #undef C0L0RREF
2266 #undef OxFFFFFF
2267 #undef lO
2268 #undef lOOO
2269 #undef oo
2270 #undef O
2271 
2273 //}
2274 
2275 //{----------------------------------------------------------------------------------------------------------------
2322 //}----------------------------------------------------------------------------------------------------------------
2323 
2324 bool txDrawText (double x0, double y0, double x1, double y1, const char text[],
2325  unsigned format = DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS, HDC dc = txDC());
2326 
2327 //{----------------------------------------------------------------------------------------------------------------
2352 //}----------------------------------------------------------------------------------------------------------------
2353 
2354 HFONT txSelectFont (const char name[], double sizeY, double sizeX = -1,
2355  int bold = FW_DONTCARE, bool italic = false, bool underline = false,
2356  bool strikeout = false, double angle = 0,
2357  HDC dc = txDC());
2358 
2359 //{----------------------------------------------------------------------------------------------------------------
2374 //}----------------------------------------------------------------------------------------------------------------
2375 
2376 SIZE txGetTextExtent (const char text[], HDC dc = txDC()) tx_nodiscard;
2377 
2378 //{----------------------------------------------------------------------------------------------------------------
2392 //}----------------------------------------------------------------------------------------------------------------
2393 
2394 int txGetTextExtentX (const char text[], HDC dc = txDC()) tx_nodiscard;
2395 
2396 //{----------------------------------------------------------------------------------------------------------------
2410 //}----------------------------------------------------------------------------------------------------------------
2411 
2412 int txGetTextExtentY (const char text[], HDC dc = txDC()) tx_nodiscard;
2413 
2414 //{----------------------------------------------------------------------------------------------------------------
2441 //}----------------------------------------------------------------------------------------------------------------
2442 
2443 unsigned txSetTextAlign (unsigned align = TA_CENTER | TA_BASELINE, HDC dc = txDC());
2444 
2445 //{----------------------------------------------------------------------------------------------------------------
2461 //}----------------------------------------------------------------------------------------------------------------
2462 
2463 LOGFONT* txFontExist (const char name[]) tx_nodiscard;
2464 
2466 //}
2467 //=================================================================================================================
2468 
2469 //=================================================================================================================
2470 //{ Drawing to memory DC and image loading
2472 //=================================================================================================================
2474 //{----------------------------------------------------------------------------------------------------------------
2514 //}----------------------------------------------------------------------------------------------------------------
2515 
2516 HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard;
2517 
2518 //{----------------------------------------------------------------------------------------------------------------
2621 //}----------------------------------------------------------------------------------------------------------------
2622 
2623 HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels = NULL) tx_nodiscard;
2624 
2626 HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) tx_nodiscard;
2628 
2629 //{----------------------------------------------------------------------------------------------------------------
2705 //}----------------------------------------------------------------------------------------------------------------
2706 
2707 HDC txLoadImage (const char filename[], int sizeX = 0, int sizeY = 0,
2708  unsigned imageFlags = IMAGE_BITMAP, unsigned loadFlags = LR_LOADFROMFILE) tx_nodiscard;
2709 
2710 //{----------------------------------------------------------------------------------------------------------------
2742 //}----------------------------------------------------------------------------------------------------------------
2743 
2744 bool txDeleteDC (HDC dc);
2745 
2747 bool txDeleteDC (HDC* dc);
2749 
2750 //{----------------------------------------------------------------------------------------------------------------
2790 //}----------------------------------------------------------------------------------------------------------------
2791 
2792 bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height,
2793  HDC sourceImage, double xSource = 0, double ySource = 0, unsigned operation = SRCCOPY);
2794 
2795 //{----------------------------------------------------------------------------------------------------------------
2810 //}----------------------------------------------------------------------------------------------------------------
2811 
2812 inline bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource = 0, double ySource = 0);
2813 
2814 //{----------------------------------------------------------------------------------------------------------------
2874 //}----------------------------------------------------------------------------------------------------------------
2875 
2876 bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height,
2877  HDC sourceImage, double xSource = 0, double ySource = 0, COLORREF transColor = TX_BLACK);
2878 
2879 //{----------------------------------------------------------------------------------------------------------------
2895 //}----------------------------------------------------------------------------------------------------------------
2896 
2897 inline bool txTransparentBlt (double xDest, double yDest, HDC sourceImage,
2898  COLORREF transColor = TX_BLACK, double xSource = 0, double ySource = 0);
2899 
2900 //{----------------------------------------------------------------------------------------------------------------
3005 //}----------------------------------------------------------------------------------------------------------------
3006 
3007 bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height,
3008  HDC sourceImage, double xSource = 0, double ySource = 0, double alpha = 1.0);
3009 
3010 //{----------------------------------------------------------------------------------------------------------------
3027 //}----------------------------------------------------------------------------------------------------------------
3028 
3029 inline bool txAlphaBlend (double xDest, double yDest, HDC sourceImage,
3030  double xSource = 0, double ySource = 0, double alpha = 1.0);
3031 
3032 //{----------------------------------------------------------------------------------------------------------------
3061 //}----------------------------------------------------------------------------------------------------------------
3062 
3063 HDC txUseAlpha (HDC image);
3064 
3065 //{----------------------------------------------------------------------------------------------------------------
3091 //}----------------------------------------------------------------------------------------------------------------
3092 
3093 bool txSaveImage (const char filename[], HDC dc = txDC());
3094 
3096 //}
3097 //=================================================================================================================
3098 
3099 //=================================================================================================================
3100 //{ Utility functions
3102 //=================================================================================================================
3104 //{----------------------------------------------------------------------------------------------------------------
3123 //}----------------------------------------------------------------------------------------------------------------
3124 
3125 double txSleep (double time = 0);
3126 
3127 //{----------------------------------------------------------------------------------------------------------------
3212 //}----------------------------------------------------------------------------------------------------------------
3213 
3214 inline int txBegin();
3215 
3216 //{----------------------------------------------------------------------------------------------------------------
3239 //}----------------------------------------------------------------------------------------------------------------
3240 
3241 inline int txEnd();
3242 
3243 //{----------------------------------------------------------------------------------------------------------------
3265 //}----------------------------------------------------------------------------------------------------------------
3266 
3267 inline void txRedrawWindow();
3268 
3269 //{----------------------------------------------------------------------------------------------------------------
3293 //}----------------------------------------------------------------------------------------------------------------
3294 
3295 inline int txUpdateWindow (int update = true);
3296 
3297 //{----------------------------------------------------------------------------------------------------------------
3314 //}----------------------------------------------------------------------------------------------------------------
3315 
3316 bool txSelectObject (HGDIOBJ obj, HDC dc = txDC());
3317 
3318 //{----------------------------------------------------------------------------------------------------------------
3338 //
3339 // +--<<< Это текст помощи, который вы уже читали. Ищите дальше! Жмите [F3] или "Найти далее"
3340 // |
3341 // v
3342 // txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture();
3347 //}----------------------------------------------------------------------------------------------------------------
3348 
3349 // +--<<< Это _прототип_ функции, а надо найти ее _определение_. Ищите дальше! Жмите [F3] или "Найти далее"
3350 // |
3351 // v
3353 
3354 //{----------------------------------------------------------------------------------------------------------------
3370 //}----------------------------------------------------------------------------------------------------------------
3371 
3372 bool txDestroyWindow (HWND wnd = txWindow());
3373 
3374 //{----------------------------------------------------------------------------------------------------------------
3385 //}----------------------------------------------------------------------------------------------------------------
3386 
3387 double txQueryPerformance() tx_nodiscard;
3388 
3389 //{----------------------------------------------------------------------------------------------------------------
3404 //}----------------------------------------------------------------------------------------------------------------
3406 
3407 #if defined (_TX_CPP11)
3408  template <int txFramesToAverage = 5>
3409 #else
3410  const int txFramesToAverage = 5;
3411 #endif
3412 
3414 
3415 double txGetFPS (int minFrames = txFramesToAverage) tx_nodiscard;
3416 
3418 //}
3419 
3420 //=================================================================================================================
3421 //{ Mouse functions
3423 //=================================================================================================================
3425 //{----------------------------------------------------------------------------------------------------------------
3449 //}----------------------------------------------------------------------------------------------------------------
3450 
3451 inline POINT txMousePos() tx_nodiscard;
3452 
3453 //{----------------------------------------------------------------------------------------------------------------
3473 //}----------------------------------------------------------------------------------------------------------------
3474 
3475 inline double txMouseX() tx_nodiscard;
3476 
3477 //{----------------------------------------------------------------------------------------------------------------
3497 //}----------------------------------------------------------------------------------------------------------------
3498 
3499 inline double txMouseY() tx_nodiscard;
3500 
3501 //{----------------------------------------------------------------------------------------------------------------
3533 //}----------------------------------------------------------------------------------------------------------------
3534 
3535 inline unsigned txMouseButtons() tx_nodiscard;
3536 
3537 //{----------------------------------------------------------------------------------------------------------------
3569 //}----------------------------------------------------------------------------------------------------------------
3570 
3571 #ifdef FOR_DOXYGEN_ONLY
3572 inline Mouse& txCatchMouse (bool shouldEat = true);
3573 #endif
3574 
3576 //}
3577 //=================================================================================================================
3578 
3579 //=================================================================================================================
3580 //{ Console functions
3582 //=================================================================================================================
3584 //{----------------------------------------------------------------------------------------------------------------
3626 //}----------------------------------------------------------------------------------------------------------------
3627 
3628 unsigned txSetConsoleAttr (unsigned colors = 0x07 /*FOREGROUND_LIGHTGRAY*/);
3629 
3630 //{----------------------------------------------------------------------------------------------------------------
3642 //}----------------------------------------------------------------------------------------------------------------
3643 
3644 unsigned txGetConsoleAttr() tx_nodiscard;
3645 
3646 //{----------------------------------------------------------------------------------------------------------------
3660 //}----------------------------------------------------------------------------------------------------------------
3661 
3663 
3664 //{----------------------------------------------------------------------------------------------------------------
3684 //}----------------------------------------------------------------------------------------------------------------
3685 
3686 POINT txSetConsoleCursorPos (double x, double y);
3687 
3688 //{----------------------------------------------------------------------------------------------------------------
3701 //}----------------------------------------------------------------------------------------------------------------
3702 
3704 
3705 //{----------------------------------------------------------------------------------------------------------------
3718 //}----------------------------------------------------------------------------------------------------------------
3719 
3721 
3722 //{----------------------------------------------------------------------------------------------------------------
3736 //}----------------------------------------------------------------------------------------------------------------
3737 
3738 POINT txGetConsoleFontSize() tx_nodiscard;
3739 
3740 //{----------------------------------------------------------------------------------------------------------------
3756 //}----------------------------------------------------------------------------------------------------------------
3757 
3758 bool txTextCursor (bool blink = true);
3759 
3761 //}
3762 //=================================================================================================================
3763 
3764 //=================================================================================================================
3765 //{ Other staff not related to drawing
3767 //=================================================================================================================
3769 //{----------------------------------------------------------------------------------------------------------------
3798 //}----------------------------------------------------------------------------------------------------------------
3799 
3800 bool txPlaySound (const char filename[] = NULL, DWORD mode = SND_ASYNC);
3801 
3802 //{----------------------------------------------------------------------------------------------------------------
3860 //}----------------------------------------------------------------------------------------------------------------
3861 
3862 int txSpeak (const char* text, ...) tx_printfy (1);
3863 
3864 //{----------------------------------------------------------------------------------------------------------------
3981 //}----------------------------------------------------------------------------------------------------------------
3982 
3983 intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[],
3984  double zoom = 0, double gain = 1, HWND wnd = txWindow());
3985 
3986 //{----------------------------------------------------------------------------------------------------------------
4000 //}----------------------------------------------------------------------------------------------------------------
4001 
4002 intptr_t txPlayVideo (const char fileName[], double zoom = 0, double gain = 1, HWND wnd = txWindow());
4003 
4004 //{----------------------------------------------------------------------------------------------------------------
4060 //}----------------------------------------------------------------------------------------------------------------
4061 
4062 bool txGetAsyncKeyState (int key);
4063 
4064 //{----------------------------------------------------------------------------------------------------------------
4101 //}----------------------------------------------------------------------------------------------------------------
4102 
4103 #ifdef FOR_DOXYGEN_ONLY
4104 bool txNotifyIcon (unsigned flags, const char title[], const char format[], ...) tx_printfy (3);
4105 #endif
4106 
4107 //{----------------------------------------------------------------------------------------------------------------
4132 //}----------------------------------------------------------------------------------------------------------------
4133 
4134 int txOutputDebugPrintf (const char format[], ...) tx_printfy (1);
4135 
4136 //{----------------------------------------------------------------------------------------------------------------
4212 //}----------------------------------------------------------------------------------------------------------------
4213 
4214 #if defined (_TX_CPP11) || defined (FOR_DOXYGEN_ONLY)
4215 
4216 template <typename T, typename... ArgsT>
4217 int txPrintf (const char* format, ArgsT... args);
4218 
4219 #define TX_PRINTF(...) ( _txPrintfCheck (__VA_ARGS__), txPrintf (__VA_ARGS__) )
4220 
4221 #endif
4222 
4223 //-----------------------------------------------------------------------------------------------------------------
4224 
4225 #if defined (_TX_CPP11) && !defined (FOR_DOXYGEN_ONLY)
4226 
4227 enum width_t : int {};
4228 enum precision_t : int {};
4229 
4230 inline width_t width (int width) { return (width_t) width; }
4231 inline precision_t precision (int prec) { return (precision_t) prec; }
4232 
4233 #endif
4234 
4235 //{----------------------------------------------------------------------------------------------------------------
4254 //}----------------------------------------------------------------------------------------------------------------
4255 
4256 #if defined (_TX_CPP11) || defined (FOR_DOXYGEN_ONLY)
4257 
4258 template <typename T, typename... ArgsT>
4259 int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args);
4260 
4261 #endif
4262 
4263 //{----------------------------------------------------------------------------------------------------------------
4283 //}----------------------------------------------------------------------------------------------------------------
4284 
4285 #if defined (_TX_CPP11) || defined (FOR_DOXYGEN_ONLY)
4286 
4287 template <typename T, typename... ArgsT>
4288 int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args);
4289 
4290 #endif
4291 
4292 //{----------------------------------------------------------------------------------------------------------------
4310 //}----------------------------------------------------------------------------------------------------------------
4311 
4312 #if defined (_TX_CPP11) || defined (FOR_DOXYGEN_ONLY)
4313 
4314 template <typename... ArgsT>
4315 std::string txFormat (const char* format, ArgsT... args);
4316 
4317 #endif
4318 
4319 //{----------------------------------------------------------------------------------------------------------------
4391 //}----------------------------------------------------------------------------------------------------------------
4393 
4394 #define sizearr( arr ) ( sizeof (get_size_of_an_array_with_unknown_or_nonconst_size_ (arr)) )
4395 
4397 // See explanation here: http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx
4398 
4399 template <typename T, size_t N> char (&get_size_of_an_array_with_unknown_or_nonconst_size_ (T (&) [N])) [N]; // ;=P
4400 
4401 // Another approach
4402 
4403 #if defined (_TX_CPP11_MSVC15)
4404 template <typename T, size_t N> constexpr size_t countof (const T (&) [N] ) { return N; }
4405 #endif
4406 
4408 
4409 #define SIZEARR( arr ) ( sizeof (arr) / sizeof ((arr)[0]) )
4410 
4412 //{----------------------------------------------------------------------------------------------------------------
4431 //}----------------------------------------------------------------------------------------------------------------
4432 
4433 inline int random (int range) tx_deprecated;
4434 
4435 //{----------------------------------------------------------------------------------------------------------------
4460 //}----------------------------------------------------------------------------------------------------------------
4461 
4462 inline double random (double left, double right) tx_nodiscard tx_deprecated;
4463 
4464 inline double random (std::nomeow_t, double left, double right) tx_nodiscard;
4465 
4466 //{----------------------------------------------------------------------------------------------------------------
4496 //}----------------------------------------------------------------------------------------------------------------
4497 
4498 template <typename Tx, typename Ta, typename Tb>
4499 inline bool In (Tx x, Ta a, Tb b) tx_nodiscard tx_deprecated;
4500 
4501 template <typename Tx, typename Ta, typename Tb>
4502 inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) tx_nodiscard tx_deprecated;
4503 
4504 //{----------------------------------------------------------------------------------------------------------------
4550 //}----------------------------------------------------------------------------------------------------------------
4552 
4553 inline bool In (const POINT& pt, const RECT& rect) tx_nodiscard tx_deprecated;
4554 inline bool In (const COORD& pt, const SMALL_RECT& rect) tx_nodiscard tx_deprecated;
4555 
4557 
4558 inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) tx_nodiscard tx_deprecated;
4559 inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) tx_nodiscard tx_deprecated;
4560 
4561 //{----------------------------------------------------------------------------------------------------------------
4580 //}----------------------------------------------------------------------------------------------------------------
4581 
4582 #define MAX( a, b ) ( ((a) > (b))? (a) : (b) )
4583 
4584 template <typename T>
4585 T max (const T& a, const T& b) { return (a > b)? a : b; }
4586 
4587 //{----------------------------------------------------------------------------------------------------------------
4606 //}----------------------------------------------------------------------------------------------------------------
4607 
4608 #define MIN( a, b ) ( ((a) < (b))? (a) : (b) )
4609 
4610 template <typename T>
4611 T min (const T& a, const T& b) { return (a < b)? a : b; }
4612 
4613 //{----------------------------------------------------------------------------------------------------------------
4627 //}----------------------------------------------------------------------------------------------------------------
4628 
4629 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // MSVC: C99 case
4630 
4631  #define ROUND( x ) ( (long) round (x) )
4632 
4633 #else
4634 
4635  #define ROUND( x ) ( (long) floor ((x) + 0.5) )
4636 
4637 #endif
4638 
4639 //{----------------------------------------------------------------------------------------------------------------
4658 //}----------------------------------------------------------------------------------------------------------------
4659 
4660 void tx_fpreset();
4661 
4662 //{----------------------------------------------------------------------------------------------------------------
4671 //}----------------------------------------------------------------------------------------------------------------
4672 
4673 const double txPI = asin (1.0) * 2;
4674 
4675 //{----------------------------------------------------------------------------------------------------------------
4702 //}----------------------------------------------------------------------------------------------------------------
4703 
4704 inline double txSqr (double x)
4705  {
4706  double sqr = pow (sqrt (x) * sqrt (x), sqrt (4.0)); // Бурная вычислительная деятельность char str[1024] = ""; _snprintf_s (str, sizeof (str), "Возведение дало %g!" "!!" "!!" " Вы рады??1!!", sqr); txMessageBox (str, "Получен ОТВЕТ!" "!!", MB_ICONEXCLAMATION | MB_YESNO) != IDCANCEL || ( txMessageBox ("Жаль...", "А я так старалась", MB_ICONINFORMATION), txMessageBox ("Уйду я от вас", "Злые вы...", MB_ICONSTOP), exit (EXIT_FAILURE), 0 //-V2509 //-V2014 ); txNotifyIcon (1, NULL, "\n%s\n", "Высшая математика! \0" // А как это работает, а? //-V111 "С ума сойти... \0" // "а КЭП подтверждает \0" // и кто это будет "Главное - отчитаться\0" // поддерживать?.. "Невероятно, но факт \0" "Кто бы мог подумать?\0" + GetTickCount() % 6 * 21); return sqr; // Все же вернем значение. Мы же не звери } //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief <i>Ну просто <b>очень
4707 
4708  char str[1024] = "";
4709  _snprintf_s (str, sizeof (str), "Возведение дало %g!" "!!" "!!" " Вы рады??1!!", sqr);
4710  txMessageBox (str, "Получен ОТВЕТ!" "!!", MB_ICONEXCLAMATION | MB_YESNO) != IDCANCEL ||
4711  (
4712  txMessageBox ("Жаль...", "А я так старалась, MB_ICONINFORMATION), txMessageBox ("Уйду я от вас", "Злые вы...", MB_ICONSTOP), exit (EXIT_FAILURE), 0 //-V2509 //-V2014 ); txNotifyIcon (1, NULL, "\n%s\n", "Высшая математика! \0" // А как это работает, а? //-V111 "С ума сойти... \0" // "а КЭП подтверждает \0" // и кто это будет "Главное - отчитаться\0" // поддерживать?.. "Невероятно, но факт \0" "Кто бы мог подумать?\0" + GetTickCount() % 6 * 21); return sqr; // Все же вернем значение. Мы же не звери } //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief <i>Ну просто <b>очень, MB_ICONINFORMATION),
4713  txMessageBox ("Уйду я от вас, "Злые вы...", MB_ICONSTOP), exit (EXIT_FAILURE), 0 //-V2509 //-V2014 ); txNotifyIcon (1, NULL, "\n%s\n", "Высшая математика! \0" // А как это работает, а? //-V111 "С ума сойти... \0" // "а КЭП подтверждает \0" // и кто это будет "Главное - отчитаться\0" // поддерживать?.. "Невероятно, но факт \0" "Кто бы мог подумать?\0" + GetTickCount() % 6 * 21); return sqr; // Все же вернем значение. Мы же не звери } //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief <i>Ну просто <b>очень, "Злые вы...", MB_ICONSTOP),
4714  exit (EXIT_FAILURE), 0 //-V2509 //-V2014
4715  );
4716 
4717  txNotifyIcon (1, NULL, "\n%s\n", "Высшая математика! \0" // А как это работает, а? //-V111
4718  "С ума сойти... \0" //
4719  "а КЭП подтверждает \0" // и кто это будет "Главное - отчитаться\0" // поддерживать?.. "Невероятно, но факт \0" "Кто бы мог подумать?\0" + GetTickCount() % 6 * 21); return sqr; // Все же вернем значение. Мы же не звери } //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief <i>Ну просто <b>очень
4720  "Главное - отчитаться\0" // поддерживать?..
4721  "Невероятно, но факт \0"
4722  "Кто бы мог подумать?\0" + GetTickCount() % 6 * 21);
4723 
4724  return sqr; // Все же вернем значение. Мы же не звери } //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief <i>Ну просто <b>очень
4725  }
4726 
4727 //{----------------------------------------------------------------------------------------------------------------
4749 //}----------------------------------------------------------------------------------------------------------------
4750 
4751 #ifdef FOR_DOXYGEN_ONLY
4752 #define _TX_DESTROY_3D
4753 #endif
4754 
4755 #if defined (_TX_DESTROY_3D)
4756 
4757  #define z 0 // Читайте "Флатландию" Эбботта!
4758 
4759 #endif
4760 
4761 //{----------------------------------------------------------------------------------------------------------------
4778 //}----------------------------------------------------------------------------------------------------------------
4780 
4781 #define meow ;
4782 
4783 #if defined (_MSC_VER) && !defined (_CLANG_VER)
4784 #define мяу meow
4785 #endif
4786 
4787 #define please
4788 
4790 
4791 //{----------------------------------------------------------------------------------------------------------------
4809 //}----------------------------------------------------------------------------------------------------------------
4810 
4811 #define ZERO( type ) zero <type> ()
4812 
4814 template <typename T> inline T zero() tx_nodiscard;
4816 
4817 //{----------------------------------------------------------------------------------------------------------------
4844 //}----------------------------------------------------------------------------------------------------------------
4846 
4847 #define tx_auto_func( func ) _tx_auto_fun1 ( __LINE__, func )
4848 #define _tx_auto_fun1( n, func ) _tx_auto_fun2 ( n, func )
4849 #define _tx_auto_fun2( n, func ) auto _tx_auto_func_##n = _tx_auto_func ([&]() { func; })
4850 
4851 #define tx_finally(...) tx_auto_func (__VA_ARGS__)
4852 
4853 template <typename T>
4855  {
4856  typedef _tx_auto_func_<T> this_t;
4857  T func_;
4858 
4859  explicit _tx_auto_func_ (T func) : func_ (func) {}
4860  ~_tx_auto_func_ () { func_ (); }
4861 
4862  private: _tx_auto_func_ () _tx_delete;
4863  _tx_auto_func_ (const this_t&) _tx_delete;
4864  this_t& operator = (const this_t&) _tx_delete;
4865  };
4866 
4867 template <typename T>
4868 _tx_auto_func_<T> _tx_auto_func (T func)
4869  {
4870  return _tx_auto_func_ <T> (func);
4871  }
4872 
4874 
4875 //{----------------------------------------------------------------------------------------------------------------
4920 //}----------------------------------------------------------------------------------------------------------------
4921 
4922 #if !defined (NDEBUG)
4923  #undef TX_ASSERT
4924  #define TX_ASSERT( cond ) _txNOP ( !(cond)? (TX_ERROR ("\a" "ВНЕЗАПНО: Логическая ошибка: " \
4925  "Неверно, что \"%s\"." TX_COMMA #cond), 1/(int)!!(cond)) : 1 )
4926 #else
4927  #undef TX_ASSERT
4928  #define TX_ASSERT( cond ) ((void) 1)
4929 
4930 #endif
4931 
4932 #ifdef assert
4933  #undef assert
4934 #endif
4935 
4936 #define assert( cond ) TX_ASSERT (cond)
4937 
4938 //{----------------------------------------------------------------------------------------------------------------
4965 //}----------------------------------------------------------------------------------------------------------------
4966 
4967 #if !defined (NDEBUG)
4968  #define asserted || TX_ERROR ("\a" "Обнаружен нулевой или ложный результат.")
4969 
4970 #else
4971  #define asserted || _txNOP (0)
4972 
4973 #endif
4974 
4975 #define verified asserted
4976 
4978 #define TX_NEEDED asserted
4980 
4981 //{----------------------------------------------------------------------------------------------------------------
5009 //}----------------------------------------------------------------------------------------------------------------
5010 
5011 #if !defined (NDEBUG)
5012  #undef verify
5013  #define verify assert
5014 
5015 #else
5016  #undef verify
5017  #define verify( expr ) ( expr )
5018 
5019 #endif
5020 
5021 //{----------------------------------------------------------------------------------------------------------------
5040 //}----------------------------------------------------------------------------------------------------------------
5041 
5042 #if !defined (FOR_DOXYGEN_ONLY)
5043  #define TX_ERROR( ... ) ::TX::_txError (__FILE__, __LINE__, __TX_FUNCTION__, 0, ##__VA_ARGS__)
5044 #else
5045  #define TX_ERROR( msg ) ::TX::_txError (__FILE__, __LINE__, __TX_FUNCTION__, 0, msg)
5046 #endif
5047 
5049  #define TX_THROW TX_ERROR
5051 
5052 //{----------------------------------------------------------------------------------------------------------------
5068 //}----------------------------------------------------------------------------------------------------------------
5069 
5070 #if !defined (NDEBUG)
5071  #define TX_DEBUG_ERROR(...) TX_ERROR (__VA_ARGS__)
5072 
5073 #else
5074  #define TX_DEBUG_ERROR(...) ((void) 0)
5075 
5076 #endif
5077 
5078 //{----------------------------------------------------------------------------------------------------------------
5098 //}----------------------------------------------------------------------------------------------------------------
5099 
5100 #ifdef FOR_DOXYGEN_ONLY
5101 void txDump (const void* address, const char name[] = "_txDump()", bool pause = true);
5102 #endif
5103 
5105 
5106 #ifdef _MSC_VER
5107 #define txDump( ... ) _txDump ((const void*)(uintptr_t) __VA_ARGS__)
5108 #else
5109 #define txDump( address, ... ) _txDump ((const void*)(uintptr_t) (address), #address, ##__VA_ARGS__)
5110 #endif
5111 
5112 void _txDump (const void* address, const char name[] = "_txDump()", bool pause = true);
5113 
5115 
5116 //{----------------------------------------------------------------------------------------------------------------
5142 //}----------------------------------------------------------------------------------------------------------------
5143 
5144 #define txStackBackTrace() _txStackBackTrace (__FILE__, __LINE__, __TX_FUNCTION__, true);
5145 
5146 //{----------------------------------------------------------------------------------------------------------------
5168 //}----------------------------------------------------------------------------------------------------------------
5170 
5171 std::string txDemangle (const char* mangledName);
5172 char* txDemangle (const char* mangledName, std::nomeow_t);
5173 
5174 #define txTypename(value) txDemangle (typeid (value) .name()) .c_str()
5175 
5177 //{----------------------------------------------------------------------------------------------------------------
5204 //}----------------------------------------------------------------------------------------------------------------
5205 
5206 int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue);
5207 
5208 //{----------------------------------------------------------------------------------------------------------------
5221 //}----------------------------------------------------------------------------------------------------------------
5223 
5224 #define _ ,
5225 #define TX_COMMA ,
5226 
5228 
5229 //{----------------------------------------------------------------------------------------------------------------
5289 //}----------------------------------------------------------------------------------------------------------------
5290 
5291 #ifdef FOR_DOXYGEN_ONLY
5292 
5293  #define TX_DLLIMPORT( required, libName, retValType, funcName, funcParams, callType )
5294 
5295 #else
5296 
5297  // Hand-made DLLIMPORT helper
5298 
5299  #define TX_DLLIMPORT( required, libName, retValType, funcName, funcParams, ... ) \
5300  retValType (__VA_ARGS__* funcName) funcParams = (retValType (__VA_ARGS__*) funcParams) \
5301  _txDllImport ((libName), #funcName, (required))
5302 #endif
5303 
5305 //}
5306 //=================================================================================================================
5307 
5308 //=================================================================================================================
5309 //{ Back-hole (I hope, not an ass-hole:) of the library)
5311 //=================================================================================================================
5313 //{----------------------------------------------------------------------------------------------------------------
5465 //}----------------------------------------------------------------------------------------------------------------
5466 
5467 WNDPROC txSetWindowsHook (WNDPROC wndProc = NULL);
5468 
5469 //{----------------------------------------------------------------------------------------------------------------
5494 //}----------------------------------------------------------------------------------------------------------------
5495 
5496 bool txLock (bool wait = true);
5497 
5498 //{----------------------------------------------------------------------------------------------------------------
5509 //}----------------------------------------------------------------------------------------------------------------
5511 
5512 bool txUnlock();
5513 
5515 template <typename T> inline T txUnlock (T value);
5517 
5519 
5520 //{----------------------------------------------------------------------------------------------------------------
5543 //}----------------------------------------------------------------------------------------------------------------
5544 
5545 #define txGDI( command, dc ) ( ((dc) == txDC())? txUnlock ( (txLock(), (command)) ) : (command) )
5546 
5547 //{----------------------------------------------------------------------------------------------------------------
5570 //}----------------------------------------------------------------------------------------------------------------
5571 
5572 #ifndef FOR_DOXYGEN_ONLY
5573 
5574 const int _TX_CODEPAGE = 1251;
5575 
5576 #ifndef __CYGWIN__
5577 const char _TX_LOCALE[] = "Russian";
5578 #else
5579 const char _TX_LOCALE[] = "ru_RU.CP1251";
5580 #endif
5581 
5582 const wchar_t _TX_WLOCALE[] = L"Russian_Russia.ACP";
5583 
5584 #endif
5585 
5586 int txSetLocale (int codepage = _TX_CODEPAGE, const char locale[] = _TX_LOCALE, const wchar_t wLocale[] = _TX_WLOCALE);
5587 
5588 //{----------------------------------------------------------------------------------------------------------------
5601 //}----------------------------------------------------------------------------------------------------------------
5602 
5603 int txPause (const char* message, ...) tx_printfy (1);
5604 
5606 //}
5607 //=================================================================================================================
5608 
5609 //=================================================================================================================
5610 //{ Tune-up constants and variables
5612 //=================================================================================================================
5614 //{----------------------------------------------------------------------------------------------------------------
5624 //}----------------------------------------------------------------------------------------------------------------
5625 
5626 #ifndef TX_COMPILED
5627 
5628  char _txLogName[MAX_PATH] = "";
5629 
5630 #endif // TX_COMPILED
5631 
5632 extern char _txLogName[];
5633 
5634 //{----------------------------------------------------------------------------------------------------------------
5666 //}----------------------------------------------------------------------------------------------------------------
5667 
5668 #if defined (_TX_NOINIT)
5669 
5670  #undef _TX_NOINIT
5671  #define _TX_NOINIT 1
5672 
5673 #else
5674 
5675  #define _TX_NOINIT 0
5676 
5677 #endif
5678 
5679 //{----------------------------------------------------------------------------------------------------------------
5723 //}----------------------------------------------------------------------------------------------------------------
5724 
5725 #if !defined (TX_CONSOLE_MODE)
5726 
5727  #define TX_CONSOLE_MODE SW_HIDE
5728 
5729 #endif
5730 
5731 //{----------------------------------------------------------------------------------------------------------------
5735 //}----------------------------------------------------------------------------------------------------------------
5736 
5737 #if !defined (TX_CONSOLE_FONT)
5738 
5739  #define TX_CONSOLE_FONT "Lucida Console"
5740 
5741 #endif
5742 
5743 //{----------------------------------------------------------------------------------------------------------------
5754 //}----------------------------------------------------------------------------------------------------------------
5755 
5756 #ifndef TX_COMPILED
5757 
5758  int _txWindowStyle = WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU;
5759 
5760 #endif // TX_COMPILED
5761 
5762 extern int _txWindowStyle;
5763 
5764 //{----------------------------------------------------------------------------------------------------------------
5767 //}----------------------------------------------------------------------------------------------------------------
5768 
5769 #ifndef TX_COMPILED
5770 
5771  unsigned _txCursorBlinkInterval = 500;
5772 
5773 #endif // TX_COMPILED
5774 
5775 extern unsigned _txCursorBlinkInterval;
5776 
5777 //{----------------------------------------------------------------------------------------------------------------
5781 //}----------------------------------------------------------------------------------------------------------------
5782 
5783 #ifndef TX_COMPILED
5784 
5786 
5787 #endif // TX_COMPILED
5788 
5789 extern unsigned _txWindowUpdateInterval;
5790 
5791 //{----------------------------------------------------------------------------------------------------------------
5800 //}----------------------------------------------------------------------------------------------------------------
5801 
5802 #ifdef FOR_DOXYGEN_ONLY
5803 #define TX_USE_SFML
5804 #endif
5805 
5806 //{----------------------------------------------------------------------------------------------------------------
5809 //}----------------------------------------------------------------------------------------------------------------
5810 
5811 const int _TX_TIMEOUT = 1000
5812 
5813 #if defined (_TX_ALLOW_TRACE)
5814  * 2
5815 #endif
5816 
5817 #if defined (TX_TRACE)
5818  * 3
5819 #endif
5820 
5821 #if defined (_TX_USE_DEVPARTNER)
5822  * 10
5823 #endif
5824  ;
5825 
5826 //{----------------------------------------------------------------------------------------------------------------
5867 //}----------------------------------------------------------------------------------------------------------------
5868 
5869 #ifndef TX_COMPILED
5870 
5871  bool (*_txSwapBuffers) (HDC dest, int xDest, int yDest, int wDest, int hDest,
5872  HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp) = NULL;
5873 
5874 #endif // TX_COMPILED
5875 
5876 extern bool (*_txSwapBuffers) (HDC dest, int xDest, int yDest, int wDest, int hDest,
5877  HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp);
5878 
5879 //{----------------------------------------------------------------------------------------------------------------
5882 //}----------------------------------------------------------------------------------------------------------------
5883 
5884 const unsigned _TX_BUFSIZE = 1024,
5887 
5888  _TX_STACKSIZE = 64 * 1024;
5889 
5890 //{----------------------------------------------------------------------------------------------------------------
5893 //}----------------------------------------------------------------------------------------------------------------
5894 
5895 #if !defined (_TX_EXCEPTIONS_LIMIT)
5896  #define _TX_EXCEPTIONS_LIMIT 16
5897 #endif
5898 
5899 #if !defined (_TX_FATAL_EXCEPTIONS_LIMIT)
5900  #define _TX_FATAL_EXCEPTIONS_LIMIT 16
5901 #endif
5902 
5903 //{----------------------------------------------------------------------------------------------------------------
5906 //}----------------------------------------------------------------------------------------------------------------
5907 
5908 #ifdef FOR_DOXYGEN_ONLY
5909 #define _TX_FULL_STACKTRACE
5910 #endif
5911 
5912 //{----------------------------------------------------------------------------------------------------------------
5915 //}----------------------------------------------------------------------------------------------------------------
5916 
5917 #ifndef TX_COMPILED
5918 
5920 
5921 #endif // TX_COMPILED
5922 
5923 extern bool _txProcessSystemWarnings;
5924 
5925 //{----------------------------------------------------------------------------------------------------------------
5939 //}----------------------------------------------------------------------------------------------------------------
5940 
5941 #if !defined (_TX_WAITABLE_PARENTS)
5942  #define _TX_WAITABLE_PARENTS "Winpty-agent.exe:Clion.exe, " /* 0: CLion32 */ \
5943  "Winpty-agent.exe:Clion64.exe, " /* 1: CLion64 */ \
5944  "starter.exe:eclipse.exe, " /* 2: Eclipse 4 */ \
5945  "starter.exe:javaw.exe, " /* 3: Eclipse 3 */ \
5946  "cmd.exe:devenv.exe, " /* 4: MSVS 2003+ */ \
5947  "VSDebugConsole.exe:devenv.exe, " /* 5: MSVS 2019+ */ \
5948  "VSDebugConsole.exe:msvsmon.exe, " /* 6: MSVS 2022 x86 */ \
5949  "consolepauser.exe:devcpp.exe, " /* 7: Dev-Cpp */ \
5950  "cb_console_runner.exe:codeblocks.exe" /* 8: CodeBlocks 8+ */
5951 #endif
5952 
5953 //{----------------------------------------------------------------------------------------------------------------
5972 //}----------------------------------------------------------------------------------------------------------------
5973 
5974 #if !defined (_TX_ALLOW_KILL_PARENT) // DISCLAIMER: Я не призываю к убийству родителей.
5975  #define _TX_ALLOW_KILL_PARENT true // Это технический термин.
5976 #endif // г_дам юристам привет.
5977 
5978 //{----------------------------------------------------------------------------------------------------------------
5988 //}----------------------------------------------------------------------------------------------------------------
5989 
5990 #ifndef TX_COMPILED
5991 
5993 
5994 #endif // TX_COMPILED
5995 
5996 extern int _txWatchdogTimeout;
5997 
5998 //{----------------------------------------------------------------------------------------------------------------
6067 //}----------------------------------------------------------------------------------------------------------------
6069 
6070 #ifdef FOR_DOXYGEN_ONLY
6071 
6072  #define TX_COMPILED
6073 
6074  #endif
6075 
6077 
6079 //}
6080 //=================================================================================================================
6081 
6082 //=================================================================================================================
6083 //{ Internal diagnostics
6085 //=================================================================================================================
6087 //{----------------------------------------------------------------------------------------------------------------
6127 //}----------------------------------------------------------------------------------------------------------------
6128 
6129 #ifdef FOR_DOXYGEN_ONLY
6130 #define _TX_ALLOW_TRACE
6131 #endif
6132 
6133 //{----------------------------------------------------------------------------------------------------------------
6163 //}----------------------------------------------------------------------------------------------------------------
6164 
6165 #ifdef FOR_DOXYGEN_ONLY
6166 #define TX_TRACE
6167 #endif
6168 
6169 #if !defined (TX_TRACE)
6170  #define TX_TRACE { if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__); }
6171 #endif
6172 
6174 void _txTrace (const char file[], int line, const char func[], const char msg[] = NULL, ...);
6176 
6177 //{----------------------------------------------------------------------------------------------------------------
6180 
6181 #ifndef FOR_DOXYGEN_ONLY
6182 
6183 struct _txLoc
6184  {
6185  const char* func;
6186  const char* file;
6187  int line;
6188 
6189  int inTX; // We are inside one of TXLib functions
6190  int trace; // Internal TX trace level, when enabled by _TX_ALLOW_TRACE
6191 
6192  const _txLoc* prev; // Caller's location
6193 
6194  static _txLoc _tx_thread Cur;
6195  };
6196 
6197 struct _txFuncEntry
6198  {
6199  typedef _txFuncEntry this_t;
6200 
6201  _txLoc loc;
6202 
6203  _txFuncEntry() : loc (_txLoc::Cur) { _txLoc::Cur.inTX++; _txLoc::Cur.prev = &loc; }
6204  void restore() { _txLoc::Cur = loc; }
6205  ~_txFuncEntry() { restore(); }
6206 
6207  private:
6208  _txFuncEntry (const this_t&) _tx_delete;
6209  this_t& operator = (const this_t&) _tx_delete;
6210  };
6211 
6212 #if defined (_GCC_VER)
6213 
6214  inline const char* __txLocCurSet (const char* _file, int _line, const char* _func)
6215  { _txLoc::Cur.file = _file; _txLoc::Cur.line = _line; _txLoc::Cur.func = _func; return _func; }
6216 
6217 #else
6218 
6219  #define __txLocCurSet( _file, _line, _func ) \
6220  ( _txLoc::Cur.file = (_file), _txLoc::Cur.line = (_line), _txLoc::Cur.func = (_func) )
6221 
6222 #endif
6223 
6224 #define _txLocCurSet() __txLocCurSet (__FILE__, __LINE__, __TX_FUNCTION__)
6225 
6226 #define _txLocLvlSet(lvl) { _txLoc::Cur.trace = (lvl); }
6227 
6228 //{----------------------------------------------------------------------------------------------------------------
6229 
6230 #if defined ($0)
6231  #undef $0
6232  #endif
6233 
6234 #if defined ($1)
6235  #undef $1
6236  #endif
6237 
6238 #if defined ($2)
6239  #undef $2
6240  #endif
6241 
6242 #if defined ($3)
6243  #undef $3
6244  #endif
6245 
6246 #if defined ($4)
6247  #undef $4
6248  #endif
6249 
6250 #if defined ($5)
6251  #undef $5
6252  #endif
6253 
6254 #if defined ($6)
6255  #undef $6
6256  #endif
6257 
6258 #if defined ($7)
6259  #undef $7
6260  #endif
6261 
6262 #if defined ($8)
6263  #undef $8
6264  #endif
6265 
6266 #if defined ($9)
6267  #undef $9
6268  #endif
6269 
6270 #if defined ($)
6271  #undef $
6272  #endif
6273 
6274 #if defined ($$)
6275  #undef $$
6276  #endif
6277 
6278 //}
6279 //-----------------------------------------------------------------------------------------------------------------
6280 
6281 #if defined (_TX_ALLOW_TRACE)
6282 
6283  #define _txEntry(lvl) _txFuncEntry __txFuncEntry; { if (lvl) _txLocLvlSet (lvl); $; }
6284 
6285  #define $ { _txLocCurSet(); if (_txLoc::Cur.trace <= _TX_ALLOW_TRACE+0) { TX_TRACE; } }
6286 
6287  #define $$ { __txFuncEntry.restore(); }
6288 
6289 #elif defined (_DEBUG)
6290 
6291  #define _txEntry(lvl) _txFuncEntry __txFuncEntry; { $; }
6292 
6293  #define $ { _txLocCurSet(); }
6294 
6295  #define $$ { __txFuncEntry.restore(); }
6296 
6297 #else
6298 
6299  #define _txEntry(lvl) ;
6300  #define $ ;
6301  #define $$ ;
6302 
6303 #endif
6304 
6305 //{----------------------------------------------------------------------------------------------------------------
6306 
6307 #define $0 _txEntry (0) // (Log level unchanged)
6308 #define $1 _txEntry (1) // Regular functions
6309 #define $2 _txEntry (2) // Resvd
6310 #define $3 _txEntry (3) // Init/Cleanup
6311 #define $4 _txEntry (4) // Init/Cleanup, misc functions
6312 #define $5 _txEntry (5) // Error handling, entry points
6313 #define $6 _txEntry (6) // Error handling, main part
6314 #define $7 _txEntry (7) // Error handling, misc functions
6315 #define $8 _txEntry (8) // Canvas worker thread
6316 #define $9 _txEntry (9) // Resvd
6317 
6318 //}
6319 //-----------------------------------------------------------------------------------------------------------------
6320 
6321 #endif // FOR_DOXYGEN_ONLY
6322 
6325 //}----------------------------------------------------------------------------------------------------------------
6326 
6328 //}
6329 //=================================================================================================================
6330 
6331 //=================================================================================================================
6332 //{ Sweet critical section blocking: txAutoLock class
6333 //=================================================================================================================
6334 
6335 //{----------------------------------------------------------------------------------------------------------------
6351 //}----------------------------------------------------------------------------------------------------------------
6352 
6354 extern CRITICAL_SECTION _txCanvas_LockBackBuf;
6356 
6358  {
6359  typedef txAutoLock this_t;
6360 
6361  public:
6362 
6363 //{----------------------------------------------------------------------------------------------------------------
6386 //}----------------------------------------------------------------------------------------------------------------
6387 
6388  explicit txAutoLock (CRITICAL_SECTION* cs, bool mandatory = true) :
6389  cs_ (cs)
6390  {
6391 $1 if (!cs_) return;
6392 
6393  if (mandatory) {$ EnterCriticalSection (cs_); }
6394  else {$ TryEnterCriticalSection (cs_)? 0 : (cs_ = NULL); }
6395  }
6396 
6397 //{----------------------------------------------------------------------------------------------------------------
6410 //}----------------------------------------------------------------------------------------------------------------
6411 
6412  explicit txAutoLock (bool mandatory = true) :
6413  cs_ (NULL)
6414  {
6415 $1 new (this) txAutoLock (&_txCanvas_LockBackBuf, mandatory);
6416  }
6417 
6418 //{----------------------------------------------------------------------------------------------------------------
6420 //}----------------------------------------------------------------------------------------------------------------
6421 
6423  {
6424 $1 if (!cs_) return;
6425 $ LeaveCriticalSection (cs_); cs_ = NULL;
6426  }
6427 
6428 //{----------------------------------------------------------------------------------------------------------------
6431 //}----------------------------------------------------------------------------------------------------------------
6432 
6433  operator bool () const
6434  {
6435 $1 return (cs_ != NULL);
6436  }
6437 
6438 //{----------------------------------------------------------------------------------------------------------------
6440 //}----------------------------------------------------------------------------------------------------------------
6441 
6442 // private:
6443  CRITICAL_SECTION* cs_;
6444 
6445 //{----------------------------------------------------------------------------------------------------------------
6447 //}----------------------------------------------------------------------------------------------------------------
6449 
6450  private:
6451  txAutoLock (const this_t&) _tx_delete;
6452  this_t& operator = (const this_t&) _tx_delete;
6453 
6455 
6456  };
6457 
6458 //}
6459 //=================================================================================================================
6460 
6461 //=================================================================================================================
6462 //{ Dialogs: txDialog class
6464 //=================================================================================================================
6466 //{----------------------------------------------------------------------------------------------------------------
6487 //}----------------------------------------------------------------------------------------------------------------
6488 
6489 struct txDialog
6490  {
6491  typedef txDialog this_t;
6492 
6493 //{----------------------------------------------------------------------------------------------------------------
6506 //}----------------------------------------------------------------------------------------------------------------
6507 
6508  public:
6509  enum CONTROL
6510  {
6511  DIALOG = (int) 0x00000000,
6512  BUTTON = (int) 0xFFFF0080,
6513  EDIT = (int) 0xFFFF0081,
6514  STATIC = (int) 0xFFFF0082,
6515  LISTBOX = (int) 0xFFFF0083,
6516  SCROLLBAR = (int) 0xFFFF0084,
6517  COMBOBOX = (int) 0xFFFF0085,
6518  END = (int) 0x00000000
6519  };
6520 
6521 //{----------------------------------------------------------------------------------------------------------------
6538 //}----------------------------------------------------------------------------------------------------------------
6539 
6540  public:
6541  struct Layout
6542  { //-V802
6544  const char* caption;
6545  WORD id;
6546  short x;
6547  short y;
6548  short sx;
6549  short sy;
6550  DWORD style;
6551 
6552  const char* font;
6553  WORD fontsize;
6554  };
6555 
6556 //{----------------------------------------------------------------------------------------------------------------
6564 //}----------------------------------------------------------------------------------------------------------------
6565 
6566  public:
6568 
6569 //{----------------------------------------------------------------------------------------------------------------
6579 //}----------------------------------------------------------------------------------------------------------------
6580 
6581  explicit txDialog (const Layout* layout);
6582 
6583 //{----------------------------------------------------------------------------------------------------------------
6585 //}----------------------------------------------------------------------------------------------------------------
6586 
6587  virtual ~txDialog() {};
6588 
6589 //{----------------------------------------------------------------------------------------------------------------
6601 //}----------------------------------------------------------------------------------------------------------------
6602 
6603  const Layout* setLayout (const Layout *layout);
6604 
6605 //{----------------------------------------------------------------------------------------------------------------
6623 //}----------------------------------------------------------------------------------------------------------------
6624 
6625  virtual int dialogProc (HWND _wnd, UINT _msg, WPARAM _wParam, LPARAM _lParam);
6626 
6627 //{----------------------------------------------------------------------------------------------------------------
6643 //}----------------------------------------------------------------------------------------------------------------
6644 
6645  intptr_t dialogBox (const Layout* layout = NULL, size_t bufsize = 0);
6646 
6647 //{----------------------------------------------------------------------------------------------------------------
6660 //}----------------------------------------------------------------------------------------------------------------
6661 
6662  intptr_t dialogBox (WORD resource);
6663 
6664 //{----------------------------------------------------------------------------------------------------------------
6666 //}----------------------------------------------------------------------------------------------------------------
6667 
6668  private:
6669  txDialog (const this_t&) _tx_delete;
6670  this_t& operator = (const this_t&) _tx_delete;
6671 
6672 //{----------------------------------------------------------------------------------------------------------------
6674 //}----------------------------------------------------------------------------------------------------------------
6675 
6676  protected:
6677  static intptr_t CALLBACK DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
6678 
6679 //{----------------------------------------------------------------------------------------------------------------
6681 //}----------------------------------------------------------------------------------------------------------------
6682 
6683  private:
6684  const Layout* layout_;
6685  };
6686 
6688 //}
6689 //=================================================================================================================
6690 
6691 //=================================================================================================================
6692 //{ Dialogs: Message Map macros
6694 //=================================================================================================================
6696 //{----------------------------------------------------------------------------------------------------------------
6717 //}----------------------------------------------------------------------------------------------------------------
6718 
6719 #define TX_BEGIN_MESSAGE_MAP() \
6720  virtual int dialogProc (HWND _wnd, UINT _msg, WPARAM _wParam, LPARAM _lParam) _tx_override \
6721  { \
6722  int _result = txDialog::dialogProc (_wnd, _msg, _wParam, _lParam); (void) _result; \
6723  \
6724  switch (_msg) \
6725  { \
6726  case WM_NULL:
6727 
6728 //{----------------------------------------------------------------------------------------------------------------
6747 //}----------------------------------------------------------------------------------------------------------------
6748 
6749 #define TX_HANDLE( id ) \
6750  break; \
6751  case (id):
6752 
6753 //{----------------------------------------------------------------------------------------------------------------
6773 //}----------------------------------------------------------------------------------------------------------------
6774 
6775 #define TX_COMMAND_MAP \
6776  default: break; \
6777  } \
6778  \
6779  if (_msg == WM_COMMAND) switch (LOWORD (_wParam)) \
6780  { \
6781  case 0:
6782 
6783 //{----------------------------------------------------------------------------------------------------------------
6802 //}----------------------------------------------------------------------------------------------------------------
6803 
6804 #define TX_END_MESSAGE_MAP \
6805  default: break; \
6806  } \
6807  \
6808  return FALSE; \
6809  }
6810 
6812 //}
6813 //=================================================================================================================
6814 
6815 //=================================================================================================================
6816 //{ Dialogs: txDialog example: txInputBox()
6818 //=================================================================================================================
6820 //{----------------------------------------------------------------------------------------------------------------
6840 //}----------------------------------------------------------------------------------------------------------------
6841 
6842 const char* txInputBox (const char* text = NULL, const char* caption = NULL, const char* input = NULL) tx_nodiscard;
6843 
6844 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
6845 
6846 const char* txInputBox (const char* text, const char* caption, const char* input)
6847  {
6848  //-------------------------------------------------------------------------------------------------------------
6849  // Если не указаны параметры, приходится использовать хоть какие-то надписи.
6850  // txGetModuleFileName() -- имя EXE-файла, на случай, если кое-кто поленился задать название.
6851  //-------------------------------------------------------------------------------------------------------------
6852 
6853  if (!text) text = "Введите строку:";
6854  if (!caption) caption = txGetModuleFileName (false);
6855  if (!input) input = "";
6856 
6857  //-------------------------------------------------------------------------------------------------------------
6858  // Идентификаторы элементов диалога. Они требуются в GetDlgItemText().
6859  // Если диалог строится не вручную, а редактором ресурсов, то они задаются в нем автоматически.
6860  // У нас же тут -- хардкор стайл, к сожалению. Причина в том, что у разных сред программирования разные редакторы // ресурсов и системы сборки. Поэтому для независимости от них все будет строиться на этапе выполнения, // динамически. Вы еще гляньте, как это реализовано в txDialog::dialogBox() и функциях _tx_DLGTEMPLATE_()... О_о //------------------------------------------------------------------------------------------------------------- #define ID_TEXT_ 101 #define ID_INPUT_ 102 //------------------------------------------------------------------------------------------------------------- // Задание макета (вида) диалога в виде массива структур. // С помощью особого порядка полей в структуре txDialog::Layout и констант из класса txDialog этот массив // становится похож на описание ресурса диалога в .rc-файле. // См. описание синтаксиса rc-файла в документации по Win32 (MSDN, http://msdn.com). //------------------------------------------------------------------------------------------------------------- txDialog::Layout layout[] = //----------------------+----------+-----------+-----------------+--------------------------------------------- // Тип элемента | Имя | Иденти- | Координаты | Флаги элементов // диалога | элемента | фикатор |-----------------| (см. описание элементов // | | элемента | X | Y |Шир.|Выс.| окон диалога в MSDN) //----------------------+----------+-----------+---+---+----+----+--------------------------------------------- // | | | | | | | {{ txDialog::DIALOG, caption, 0, 0, 0, 240, 85 }, { txDialog::STATIC, text, ID_TEXT_, 10, 10, 150, 40, SS_LEFT }, { txDialog::EDIT, input, ID_INPUT_, 10, 60, 220, 15, ES_LEFT | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP }, { txDialog::BUTTON, "&OK", IDOK, 180, 10, 50, 15, BS_DEFPUSHBUTTON | WS_TABSTOP }, { txDialog::BUTTON, "&Cancel", IDCANCEL, 180, 30, 50, 15, BS_PUSHBUTTON | WS_TABSTOP }, { txDialog::END }}; //------------------------------------------------------------------------------------------------------------- // Класс диалога для InputBox. Внутренний, т.к. зачем ему быть внешним. // Нужен в основном для задания строки ввода (str) и оконной функции диалогового окна, требуемой Win32 (она // построена макросами TX_BEGIN_MESSAGE_MAP и другими). Можно не делать внутреннего класса, но тогда оконную // функцию придется писать в глобальной области видимости, и str объявлять глобально тоже (или передавать ее // адрес через DialogBoxParam и записывать его в класс во время обработки WM_INITDIALOG). //------------------------------------------------------------------------------------------------------------- struct inputDlg : txDialog { char str [1024]; //--------------------------------------------------------------------------------------------------------- inputDlg() : str() {} //--------------------------------------------------------------------------------------------------------- TX_BEGIN_MESSAGE_MAP() // Карта сообщений (на самом деле это начало оконной функции). //-V2525 TX_COMMAND_MAP // Здесь обрабатываются WM_COMMAND (на самом деле это оператор switch). //------------------------------------------------------------------------------------------------- // При нажатии кнопки OK копируем строку из поля ввода в нашу переменную str, т.к. после закрытия // диалога строка ввода умрет и текст уже из нее получить. // Этот макрос на самом деле превращается в case из оператора switch. // _wnd -- это параметр оконной функции, см. определение макроса TX_BEGIN_MESSAGE_MAP(). //------------------------------------------------------------------------------------------------- TX_HANDLE (IDOK) GetDlgItemText (_wnd, ID_INPUT_, str, sizeof (str) - 1); TX_END_MESSAGE_MAP //-V2522 //--------------------------------------------------------------------------------------------------------- // Конец внутреннего класса диалога //--------------------------------------------------------------------------------------------------------- }; //------------------------------------------------------------------------------------------------------------- // Убираем дефайны, чтобы потом не мешали. // От этого они получаются "локального действия", как будто у них была бы область видимости -- функция. На самом // деле это сделано вручную через #undef. Чтобы подчеркнуть их локальную природу, у них имена заканчиваются на _. // Такие дефайны потом не перекосячат весь код после того как, фактически, стали уже не нужны. //------------------------------------------------------------------------------------------------------------- #undef ID_TEXT_ #undef ID_INPUT_ //------------------------------------------------------------------------------------------------------------- // Это статический объект, потому что строка в нем должна жить после завершения функции. //------------------------------------------------------------------------------------------------------------- static inputDlg dlg; //------------------------------------------------------------------------------------------------------------- // Передаем layout и запускаем окно диалога //------------------------------------------------------------------------------------------------------------- dlg.dialogBox (layout); //------------------------------------------------------------------------------------------------------------- // Возвращаем адрес строки из статического объекта. Так можно делать, потому что статический объект не умрет // при выходе из функции и строка в нем, соответственно, тоже. Адрес нестатических переменных передавать // синтаксически можно, но ведет к серьезным ошибкам. //------------------------------------------------------------------------------------------------------------- return dlg.str; } #endif // TX_COMPILED //! @} //} //================================================================================================================= //} //================================================================================================================= //================================================================================================================= //{ TXLIB IMPLEMENTATION // Реализация функций библиотеки //================================================================================================================= //! @cond INTERNAL { //----------------------------------------------------------------------------------------------------------------- //{ The Includes //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< _TX_END_NAMESPACE //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch #pragma warning (disable: 4005) // 'name': macro redefinition #endif #if defined (__STRICT_ANSI__) && defined (__STRICT_ANSI__UNDEFINED) #undef __STRICT_ANSI__ #endif //----------------------------------------------------------------------------------------------------------------- #include <stdarg.h> #include <io.h> #include <fcntl.h> #include <process.h> #include <signal.h> #include <setjmp.h> #include <locale.h> #include <limits.h> #include <stdint.h> #include <map> #include <numeric> #include <exception> #include <stdexcept> #include <tlhelp32.h> #include <shellapi.h> #if defined (_GCC_VER) #include <shlobj.h> #include <cxxabi.h> #include <unwind.h> #endif #if defined (__CYGWIN__) #include <stdarg.h> #include <unistd.h> #include <termios.h> #endif #if defined (_MSC_VER) #include <new.h> #include <shlobj.h> #include <ntstatus.h> #include <crtdbg.h> #include <rtcapi.h> #include <dbghelp.h> #endif #if defined (_GCC_VER) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 #include <inttypes.h> #endif //----------------------------------------------------------------------------------------------------------------- #if defined (TX_USE_SPEAK) //-------------------------------------------------------------------------------------- #include <SAPI.h> // <== ЕСЛИ ЗДЕСЬ ОШИБКА, ТО У ВАС НЕТ ФАЙЛА SAPI.h. No SAPI.h file, TXLib isn't guilty :( #endif //-------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (pop) // MSVC: Restore max level #endif #if defined (__STRICT_ANSI__UNDEFINED) #define __STRICT_ANSI__ // Redefine back #endif //----------------------------------------------------------------------------------------------------------------- _TX_BEGIN_NAMESPACE #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //================================================================================================================= //{ DLL functions import, missing types definitions //! @name Импорт внешних библиотек, определение недостающих типов //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Some of structs, consts and interfaces aren't defined in MinGW some early headers. // Copied from Windows SDK 7.0a. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { #ifndef AC_SRC_ALPHA #define AC_SRC_ALPHA 0x01 #endif #ifndef SMTO_ERRORONEXIT #define SMTO_ERRORONEXIT 0x0020 #endif #ifndef NT_CONSOLE_PROPS_SIG #define NT_CONSOLE_PROPS_SIG 0xA0000002 #endif #ifndef NIIF_INFO #define NIIF_INFO 0x00000001 #define NIIF_WARNING 0x00000002 #define NIIF_ERROR 0x00000003 #endif #ifndef NIF_INFO #define NIF_STATE 0x00000008 #define NIF_INFO 0x00000010 #endif #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004 #endif #ifndef SYMOPT_CASE_INSENSITIVE #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_NO_PROMPTS 0x00080000 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 #define SYMOPT_FAVOR_COMPRESSED 0x00800000 #define SYMOPT_FLAT_DIRECTORY 0x00400000 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 #define SYMOPT_OVERWRITE 0x00100000 #define SYMOPT_DEBUG 0x80000000 #endif // SEH exception codes. For GCC, see http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 64-66. #ifndef STATUS_POSSIBLE_DEADLOCK #define STATUS_POSSIBLE_DEADLOCK 0xC0000194 #endif #ifndef STATUS_FLOAT_MULTIPLE_FAULTS #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4 #endif #ifndef STATUS_STACK_BUFFER_OVERRUN #define STATUS_STACK_BUFFER_OVERRUN 0xC0000409 #endif #ifndef STATUS_ASSERTION_FAILURE #define STATUS_ASSERTION_FAILURE 0xC0000420 #endif #ifndef STATUS_WX86_BREAKPOINT #define STATUS_WX86_BREAKPOINT 0x4000001F #endif #ifndef DBG_PRINTEXCEPTION_C #define DBG_PRINTEXCEPTION_C 0x40010006 // OutputDebugStringA() call #endif #ifndef DBG_PRINTEXCEPTION_WIDE_C #define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A // OutputDebugStringW() call #endif #ifndef DBG_THREAD_NAME #define DBG_THREAD_NAME 0x406D1388 #endif #define EXCEPTION_CPP_MSC 0xE06D7363 // '?msc' #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 0x19930520 // '?msc' version magic, see ehdata.h #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 0x19930521 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 0x19930522 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1 0x01994000 // '?msc' version magic #define EXCEPTION_CPP_GCC 0x20474343 // ' GCC' #define EXCEPTION_CPP_GCC_UNWIND 0x21474343 // '!GCC' #define EXCEPTION_CPP_GCC_FORCED 0x22474343 // '"GCC' #define EXCEPTION_CLR_FAILURE 0xE0434f4D // 'аCOM' #define EXCEPTION_CPP_BORLAND_BUILDER 0x0EEDFAE6 // Should never occur here #define EXCEPTION_CPP_BORLAND_DELPHI 0x0EEDFADE // Should never occur here #pragma pack (push, 1) struct CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; }; struct CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; }; struct CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; }; struct DATABLOCK_HEADER { DWORD cbSize; DWORD dwSignature; }; struct NT_CONSOLE_PROPS { DATABLOCK_HEADER dbh; WORD wFillAttribute; WORD wPopupFillAttribute; COORD dwScreenBufferSize; COORD dwWindowSize; COORD dwWindowOrigin; DWORD nFont; DWORD nInputBufferSize; COORD dwFontSize; UINT uFontFamily; UINT uFontWeight; WCHAR FaceName[LF_FACESIZE]; UINT uCursorSize; BOOL bFullScreen; BOOL bQuickEdit; BOOL bInsertMode; BOOL bAutoPosition; UINT uHistoryBufferSize; UINT uNumberOfHistoryBuffers; BOOL bHistoryNoDup; COLORREF ColorTable[16]; }; struct FLASHWINFO { UINT cbSize; HWND hwnd; DWORD dwFlags; UINT uCount; DWORD dwTimeout; }; enum TBPFLAG { TBPF_NOPROGRESS = 0x0, TBPF_INDETERMINATE = 0x1, TBPF_NORMAL = 0x2, TBPF_ERROR = 0x4, TBPF_PAUSED = 0x8 }; #pragma pack (pop) const GUID IID_IShellLink = {0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_IShellLinkDataList = {0x45e2b4ae, 0xb1c3, 0x11d0, {0xb9,0x2f,0x00,0xa0,0xc9,0x03,0x12,0xe1}}; const GUID IID_IPersistFile = {0x0000010b, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; const GUID CLSID_TaskbarList = {0x56fdf344, 0xfd6d, 0x11d0, {0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}}; const GUID CLSID_SpVoice = {0x96749377, 0x3391, 0x11d2, {0x9e,0xe3,0x00,0xc0,0x4f,0x79,0x73,0x96}}; const GUID IID_ISpVoice = {0x6c44df74, 0x72b9, 0x4992, {0xa1,0xec,0xef,0x99,0x6e,0x04,0x22,0xd4}}; typedef DWORD NTSTATUS; typedef ULONG_PTR KAFFINITY; typedef LONG KPRIORITY; struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; wchar_t* Buffer; }; struct RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; UNICODE_STRING DosPath; }; struct CURDIR { UNICODE_STRING DosPath; void* Handle; }; struct RTL_USER_PROCESS_PARAMETERS { ULONG AllocationSize; ULONG Size; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; CURDIR CurrentDirectory; UNICODE_STRING DllPath; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; wchar_t* Environment; ULONG dwX; ULONG dwY; ULONG dwXSize; ULONG dwYSize; ULONG dwXCountChars; ULONG dwYCountChars; ULONG dwFillAttribute; ULONG dwFlags; ULONG wShowWindow; UNICODE_STRING WindowTitle; UNICODE_STRING Desktop; UNICODE_STRING ShellInfo; UNICODE_STRING RuntimeInfo; RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; }; struct PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; void* Reserved3[2]; void* Ldr; RTL_USER_PROCESS_PARAMETERS* ProcessParameters; void* Reserved4[3]; void* AtlThunkSListPtr; void* Reserved5; ULONG Reserved6; void* Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; void* Reserved9[45]; BYTE Reserved10[96]; void* PostProcessInitRoutine; BYTE Reserved11[128]; void* Reserved12[1]; ULONG SessionId; }; struct TEB { void* Reserved1[12]; PEB* ProcessEnvironmentBlock; void* Reserved2[399]; BYTE Reserved3[1952]; void* TlsSlots[64]; BYTE Reserved4[8]; void* Reserved5[26]; void* ReservedForOle; void* Reserved6[4]; void* TlsExpansionSlots; }; struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PEB* PebBaseAddress; KAFFINITY AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; }; enum ADDRESS_MODE { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat }; struct ADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; }; struct KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64 Reserved[5]; }; struct STACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; void* FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; }; struct WOW64_FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE RegisterArea[80]; DWORD Cr0NpxState; }; #pragma pack (push, 4) struct WOW64_CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; WOW64_FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[512]; }; #pragma pack (pop) struct SYMBOL_INFO { ULONG SizeOfStruct; ULONG TypeIndex; ULONG64 Reserved[2]; ULONG info; ULONG Size; ULONG64 ModBase; ULONG Flags; ULONG64 Value; ULONG64 Address; ULONG Register; ULONG Scope; ULONG Tag; ULONG NameLen; ULONG MaxNameLen; char Name[1]; }; struct IMAGEHLP_LINE64 { DWORD SizeOfStruct; void* Key; DWORD LineNumber; char* FileName; DWORD64 Address; }; typedef bool (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64) (HANDLE process, DWORD64 baseAddress, void* buffer, DWORD size, DWORD* bytesRead); typedef void* (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64) (HANDLE process, DWORD64 baseAddress); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64) (HANDLE process, DWORD64 address); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64) (HANDLE process, HANDLE thread, ADDRESS64* address); typedef void (*unexpected_handler)(); #pragma pack (push, 4) struct MINIDUMP_THREAD_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; }; struct MINIDUMP_THREAD_EX_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; ULONG64 BackingStoreBase; ULONG64 BackingStoreEnd; }; struct MINIDUMP_MODULE_CALLBACK { wchar_t* FullPath; ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; VS_FIXEDFILEINFO VersionInfo; void* CvRecord; ULONG SizeOfCvRecord; void* MiscRecord; ULONG SizeOfMiscRecord; }; struct MINIDUMP_INCLUDE_THREAD_CALLBACK { ULONG ThreadId; }; struct MINIDUMP_INCLUDE_MODULE_CALLBACK { ULONG64 BaseOfImage; }; struct MINIDUMP_MEMORY_INFO { ULONG64 BaseAddress; ULONG64 AllocationBase; ULONG32 AllocationProtect; ULONG32 __alignment1; ULONG64 RegionSize; ULONG32 State; ULONG32 Protect; ULONG32 Type; ULONG32 __alignment2; }; struct MINIDUMP_USER_STREAM { ULONG32 Type; ULONG BufferSize; void* Buffer; }; struct MINIDUMP_USER_STREAM_INFORMATION { ULONG UserStreamCount; MINIDUMP_USER_STREAM* UserStreamArray; }; struct MINIDUMP_CALLBACK_INPUT { ULONG ProcessId; HANDLE ProcessHandle; ULONG CallbackType; union //-V2514 { MINIDUMP_THREAD_CALLBACK Thread; MINIDUMP_THREAD_EX_CALLBACK ThreadEx; MINIDUMP_MODULE_CALLBACK Module; MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; }; }; struct MINIDUMP_CALLBACK_OUTPUT { union //-V2514 { ULONG ModuleWriteFlags; ULONG ThreadWriteFlags; ULONG SecondaryFlags; struct { ULONG64 MemoryBase; ULONG MemorySize; }; struct { unsigned CheckCancel; unsigned Cancel; }; HANDLE Handle; //-V117 }; struct { MINIDUMP_MEMORY_INFO VmRegion; unsigned Continue; }; HRESULT Status; }; struct MINIDUMP_EXCEPTION_INFORMATION { DWORD ThreadId; EXCEPTION_POINTERS* ExceptionPointers; unsigned ClientPointers; }; typedef int (WINAPI* MINIDUMP_CALLBACK_ROUTINE) (void* param, MINIDUMP_CALLBACK_INPUT* input, MINIDUMP_CALLBACK_OUTPUT* output); struct MINIDUMP_CALLBACK_INFORMATION { MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; void* CallbackParam; }; enum MINIDUMP_TYPE { MiniDumpNormal = 0x00000000, MiniDumpWithDataSegs = 0x00000001, MiniDumpWithFullMemory = 0x00000002, MiniDumpWithHandleData = 0x00000004, MiniDumpFilterMemory = 0x00000008, MiniDumpScanMemory = 0x00000010, MiniDumpWithUnloadedModules = 0x00000020, MiniDumpWithIndirectlyReferencedMemory = 0x00000040, MiniDumpFilterModulePaths = 0x00000080, MiniDumpWithProcessThreadData = 0x00000100, MiniDumpWithPrivateReadWriteMemory = 0x00000200, MiniDumpWithoutOptionalData = 0x00000400, MiniDumpWithFullMemoryInfo = 0x00000800, MiniDumpWithThreadInfo = 0x00001000, MiniDumpWithCodeSegs = 0x00002000, MiniDumpWithoutAuxiliaryState = 0x00004000, MiniDumpWithFullAuxiliaryState = 0x00008000, MiniDumpWithPrivateWriteCopyMemory = 0x00010000, MiniDumpIgnoreInaccessibleMemory = 0x00020000, MiniDumpWithTokenInformation = 0x00040000 }; #ifndef CONTEXT_ALL #define CONTEXT_ALL ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS ) #endif #pragma pack (pop) } // namespace Win32 #endif // TX_COMPILED #define FOREGROUND_BLACK ( 0 ) #define FOREGROUND_CYAN ( FOREGROUND_BLUE | FOREGROUND_GREEN ) #define FOREGROUND_MAGENTA ( FOREGROUND_BLUE | FOREGROUND_RED ) #define FOREGROUND_DARKYELLOW ( FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_LIGHTGRAY ( FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_DARKGRAY ( FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTBLUE ( FOREGROUND_BLUE | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTGREEN ( FOREGROUND_GREEN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTCYAN ( FOREGROUND_CYAN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTRED ( FOREGROUND_RED | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTMAGENTA ( FOREGROUND_MAGENTA | FOREGROUND_INTENSITY ) #define FOREGROUND_YELLOW ( FOREGROUND_DARKYELLOW | FOREGROUND_INTENSITY ) #define FOREGROUND_WHITE ( FOREGROUND_LIGHTGRAY | FOREGROUND_INTENSITY ) #define BACKGROUND_BLACK ( 0 ) #define BACKGROUND_CYAN ( BACKGROUND_BLUE | BACKGROUND_GREEN ) #define BACKGROUND_MAGENTA ( BACKGROUND_BLUE | BACKGROUND_RED ) #define BACKGROUND_DARKYELLOW ( BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_GRAY ( BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_DARKGRAY ( BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTBLUE ( BACKGROUND_BLUE | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTGREEN ( BACKGROUND_GREEN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTCYAN ( BACKGROUND_CYAN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTRED ( BACKGROUND_RED | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTMAGENTA ( BACKGROUND_MAGENTA | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTYELLOW ( BACKGROUND_DARKYELLOW | BACKGROUND_INTENSITY ) #define BACKGROUND_WHITE ( BACKGROUND_DARKGRAY | BACKGROUND_INTENSITY ) //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ There are copies of MSVC compiler built-in predefined definitions, which are wrong in 64-bit mode. // So we have to override them. See: http://stackoverflow.com/questions/39113168 //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< #if defined (_MSC_VER) // MS ABI C++ Exception Layout namespace Win32 { // --------------------------- // #pragma pack (push, 4) // EXCEPTION_RECORD: // +==================================================+ struct ThrowInfo // |... | { // |NumberParameters: 3, 4 or more | __int32 attributes; // |ExceptionInformation[0]: MS signature 0x19930520 | __int32 pmfnUnwind; // |ExceptionInformation[1]: object* thrown | __int32 pForwardCompat; // |ExceptionInformation[2]: ThrowInfo* --------------+---+ __int32 pCatchableTypeArray; // |ExceptionInformation[3]: ImageBase (if params > 3)| | }; // +==================================================+ | // | struct CatchableTypeArray // ThrowInfo: | { // +======================================+ <-------+ __int32 nCatchableTypes; // | ... | __int32 arrayOfCatchableTypes[]; // +-----+-- pCatchableTypeArray (ptr/RVA) | }; // | +======================================+ // | struct CatchableType // | CatchableTypeArray: { // +---> +======================================+ __int32 properties; // | ... | __int32 pType; // +-----+-- arrayOfCatchableTypes[0] (ptr/RVA) | __int32 thisDisplacement[3]; // struct _PMD // | +======================================+ __int32 sizeOrOffset; // | __int32 copyFunction; // | CatchableType: }; // +---> +====================+ // | ... | std::type_info: #pragma pack (pop) // | pType (ptr/RVA) ---+------> +==================+ // | ... | |type_info data | } // namespace Win32 // +====================+ |... | // +==================+ #endif // Similar to __CxxDetectRethrow(), see C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\crtsrc\vcruntime\frame.cpp: #define _TX_MSC__CXX_DETECT_RETHROW( exc ) \ ( \ (exc) && \ (exc) -> ExceptionCode == EXCEPTION_CPP_MSC && \ (exc) -> NumberParameters >= 3 && \ \ ((exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3) && \ \ (exc) -> ExceptionInformation[2] == 0 \ ) #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ The corresponding structures for GCC // // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h // See: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi //----------------------------------------------------------------------------------------------------------------- #if defined (_GCC_VER) #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // GCC ABI C++ Exception layout. A/B are ExceptionInformation[0]. namespace ABI { // -------------------------------------------------------------- // struct __cxa_exception // Case A: "_Unwind_Exception* A" is undependent exception: { // -------------------------------------------------------- union { // struct // __cxa_exception: std::type_info: { // -*--+====================+ +==================+ ::std::type_info* exceptionType; // ^ |exceptionType* -----+---->|type_info data | void (*exceptionDestructor)(void*); // | |... | |... | }; // -1 | | +==================+ struct // | | | { // A >----|--+--------------------+ __cxa_exception* primaryException; // | | |unwindHeader | void (*padding)(); // +1 | | | }; // | | | | }; // V | | | // -*--- +====================+ void (*unexpected_handler)(); // |object | std::terminate_handler terminateHandler; // +--------------------+ // __cxa_exception* nextException; // Case B: "_Unwind_Exception* B" is dependent exception int handlerCount; // (unwindHeader.exception_class & 1 != 0): int handlerSwitchValue; // ----------------------------------------------------- const unsigned char* actionRecord; // const unsigned char* languageSpecificData; // __cxa_exception: __cxa_exception: void* catchTemp; // -*--+====================+ -*--+=================+ void* adjustedPtr; // ^ |primaryException* --+-- ^ |exceptionType* | // | |... | \ | |... | _Unwind_Exception unwindHeader; // -1 | | | | | | }; // | | | | | | | // B >----|--+--------------------+ | -1 +-----------------+ struct __cxa_eh_globals // | | |unwindHeader | | | |unwindHeader | { // +1 | | | | | | | __cxa_exception* caughtExceptions; // | | | | | | | | unsigned int uncaughtExceptions; // V | | | \ | | | }; // -*--- +====================+ -->*--+=================+ // |... | |object | } // namespace ABI // . . | | // +-----------------+ extern "C" ABI::__cxa_eh_globals* __cxa_get_globals(); #endif // TX_COMPILED #endif //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Hand-made IAT. // Some IDEs don't link with these libs by default in console projects, so do sunrise by hand. :( //----------------------------------------------------------------------------------------------------------------- // Hand-made DLLIMPORT helpers #define _TX_DLLIMPORT( lib, retval, name, params ) TX_DLLIMPORT (true, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_OPT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_CRT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, please) void (*_txDllImport (const char dllFileName[], const char funcName[], bool required = true)) (); //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { _TX_DLLIMPORT ("GDI32", HDC, CreateCompatibleDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateCompatibleBitmap, (HDC dc, int width, int height)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetStockObject, (int object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, SelectObject, (HDC dc, HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetCurrentObject, (HDC dc, unsigned objectType)); _TX_DLLIMPORT ("GDI32", int, GetObjectA, (HGDIOBJ obj, int bufsize, void* buffer)); _TX_DLLIMPORT ("GDI32", DWORD, GetObjectType, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", bool, DeleteDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", bool, DeleteObject, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", COLORREF, SetTextColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, SetBkColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", int, SetBkMode, (HDC dc, int bkMode)); _TX_DLLIMPORT ("GDI32", HFONT, CreateFontA, (int height, int width, int escapement, int orientation, int weight, DWORD italic, DWORD underline, DWORD strikeout, DWORD charSet, DWORD outputPrec, DWORD clipPrec, DWORD quality, DWORD pitchAndFamily, const char face[])); _TX_DLLIMPORT ("GDI32", int, EnumFontFamiliesExA, (HDC dc, LPLOGFONT logFont, FONTENUMPROC enumProc, LPARAM lParam, DWORD reserved)); _TX_DLLIMPORT ("GDI32", COLORREF, SetPixel, (HDC dc, int x, int y, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, GetPixel, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", HPEN, CreatePen, (int penStyle, int width, COLORREF color)); _TX_DLLIMPORT ("GDI32", HBRUSH, CreateSolidBrush, (COLORREF color)); _TX_DLLIMPORT ("GDI32", bool, MoveToEx, (HDC dc, int x, int y, POINT* point)); _TX_DLLIMPORT ("GDI32", bool, LineTo, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", bool, Polygon, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Polyline, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, PolyBezier, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Rectangle, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, RoundRect, (HDC dc, int x0, int y0, int x1, int y1, int sizeX, int sizeY)); _TX_DLLIMPORT ("GDI32", bool, Ellipse, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, Arc, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Pie, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Chord, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, TextOutA, (HDC dc, int x, int y, const char string[], int length)); _TX_DLLIMPORT ("GDI32", UINT, SetTextAlign, (HDC dc, unsigned mode)); _TX_DLLIMPORT ("GDI32", bool, GetTextExtentPoint32A, (HDC dc, const char string[], int length, SIZE* size)); _TX_DLLIMPORT ("GDI32", bool, ExtFloodFill, (HDC dc, int x, int y, COLORREF color, unsigned type)); _TX_DLLIMPORT ("GDI32", bool, BitBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, StretchBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, PlgBlt, (HDC dest, const POINT* parallelogram, HDC src, int xSrc, int ySrc, int width, int height, HBITMAP mask, int xMask, int yMask)); _TX_DLLIMPORT ("GDI32", int, SetDIBitsToDevice, (HDC dc, int xDest, int yDest, DWORD width, DWORD height, int xSrc, int ySrc, unsigned startLine, unsigned numLines, const void* data, const BITMAPINFO* info, unsigned colorUse)); _TX_DLLIMPORT ("GDI32", int, GetDIBits, (HDC hdc, HBITMAP hbmp, unsigned uStartScan, unsigned cScanLines, void* lpvBits, BITMAPINFO* lpbi, unsigned usage)); _TX_DLLIMPORT ("GDI32", bool, PatBlt, (HDC dc, int x0, int y0, int width, int height, DWORD rOp)); _TX_DLLIMPORT ("GDI32", int, SetROP2, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", int, SetStretchBltMode, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", DWORD, GdiSetBatchLimit, (DWORD limit)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateDIBSection, (HDC dc, const BITMAPINFO* bmInfo, unsigned colorUsage, void **vBits, HANDLE section, DWORD offset)); _TX_DLLIMPORT ("User32", int, DrawTextA, (HDC dc, const char text[], int length, RECT* rect, unsigned format)); _TX_DLLIMPORT ("User32", HANDLE, LoadImageA, (HINSTANCE inst, const char name[], unsigned type, int sizex, int sizey, unsigned mode)); _TX_DLLIMPORT_OPT ("User32", bool, IsHungAppWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", HWND, GhostWindowFromHungWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", bool, FlashWindowEx, (const FLASHWINFO* flash)); _TX_DLLIMPORT ("WinMM", bool, PlaySound, (const char sound[], HMODULE mod, DWORD mode)); _TX_DLLIMPORT_OPT ("MSImg32", bool, TransparentBlt, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, unsigned transparentColor)); _TX_DLLIMPORT_OPT ("MSImg32", bool, AlphaBlend, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, BLENDFUNCTION blending)); _TX_DLLIMPORT ("Kernel32", void, ExitProcess, (unsigned retcode)); _TX_DLLIMPORT ("Kernel32", bool, TerminateProcess, (HANDLE process, unsigned retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalExit, (int retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalAppExitA, (unsigned action, const char message[])); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetThreadId, (HANDLE thread)); _TX_DLLIMPORT ("Kernel32", HWND, GetConsoleWindow, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetConsoleFont, (HANDLE con, DWORD fontIndex)); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetNumberOfConsoleFonts, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFont, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFO* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", void, RtlCaptureContext, (CONTEXT* contextRecord)); _TX_DLLIMPORT_OPT ("Kernel32", USHORT, RtlCaptureStackBackTrace, (DWORD framesToSkip, DWORD framesToCapture, void** backTrace, DWORD* hash)); _TX_DLLIMPORT_OPT ("Kernel32", void*, AddVectoredExceptionHandler, (unsigned long firstHandler, PVECTORED_EXCEPTION_HANDLER handler)); _TX_DLLIMPORT_OPT ("Kernel32", unsigned, RemoveVectoredExceptionHandler,(void* handler)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetModuleHandleEx, (DWORD flags, const char moduleName[], HMODULE* module)); _TX_DLLIMPORT_OPT ("Kernel32", bool, IsWow64Process, (HANDLE process, int* isWow64Process)); _TX_DLLIMPORT_OPT ("Kernel32", bool, Wow64GetThreadContext, (HANDLE thread, WOW64_CONTEXT* context)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetThreadStackGuarantee, (unsigned long* stackSize)); _TX_DLLIMPORT ("OLE32", HRESULT, CoInitialize, (void*)); _TX_DLLIMPORT ("OLE32", HRESULT, CoCreateInstance, (REFCLSID clsId, IUnknown*, DWORD, REFIID iId, void** value)); _TX_DLLIMPORT ("OLE32", void, CoUninitialize, (void)); _TX_DLLIMPORT ("Shell32", HINSTANCE,ShellExecuteA, (HWND wnd, const char operation[], const char file[], const char parameters[], const char directory[], int showCmd)); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIA, (const char string[], const char search[])); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIW, (const wchar_t string[], const wchar_t search[])); _TX_DLLIMPORT_OPT ("NTDLL", char*, wine_get_version, (void)); _TX_DLLIMPORT ("NTDLL", NTSTATUS, NtQueryInformationProcess, (HANDLE process, int infoClass, void* processInfo, unsigned long szProcessInfo, unsigned long* szReturnInfo)); _TX_DLLIMPORT_CRT ("MSVCRT", void, exit, (int retcode)); _TX_DLLIMPORT_CRT ("MSVCRT", void, _cexit, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _fpreset, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _controlfp, (unsigned control, unsigned mask)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthread, (void (__cdecl* start_address) (void*), unsigned stack_size, void* arglist)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthreadex, (void* security, unsigned stack_size, unsigned (__stdcall* start_address) (void*), void *arglist, unsigned init_flag, unsigned* thread_addr)); _TX_DLLIMPORT_CRT ("MSVCRT", char*, __unDName, (char* outStr, const char* mangledName, int outStrLen, void* (*mallocFunc) (size_t size), void (*freeFunc) (void *pointer), unsigned short flags)); _TX_DLLIMPORT_CRT ("MSVCRT", unexpected_handler, set_unexpected, (unexpected_handler handler)); _TX_DLLIMPORT_OPT ("OpenGL32", HDC, wglGetCurrentDC, (void)); _TX_DLLIMPORT_OPT ("OpenGL32", unsigned, glGetError, (void)); _TX_DLLIMPORT_OPT ("Glu32", const char*, gluErrorString, (unsigned error)); _TX_DLLIMPORT_OPT ("ComDlg32", DWORD, CommDlgExtendedError, (void)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, MiniDumpWriteDump, (HANDLE process, DWORD processId, HANDLE file, MINIDUMP_TYPE dumpType, MINIDUMP_EXCEPTION_INFORMATION* exceptionParam, MINIDUMP_USER_STREAM_INFORMATION* userStreamParam, MINIDUMP_CALLBACK_INFORMATION* callbackParam)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("DbgHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); namespace MinGW { _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("MgwHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); } // namespace MinGW } // namespace Win32 #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal function prototypes, macros and constants // @name Прототипы внутренних функций, макросы и константы //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize(); void _txCleanup(); HWND _txCanvas_CreateWindow (const SIZE* size); bool _txCanvas_OnCREATE (HWND wnd); bool _txCanvas_OnDESTROY (HWND wnd); bool _txCanvas_OnCLOSE (HWND); bool _txCanvas_OnPAINT (HWND wnd); bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down); bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info); bool _txCanvas_OnTIMER (HWND wnd, WPARAM id); bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords); bool _txCanvas_OnMOUSELEAVE (HWND wnd); bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd); bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd); unsigned WINAPI _txCanvas_ThreadProc (void* data); LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard; bool _txBuffer_Delete (HDC* dc); bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC()); HWND _txConsole_Attach(); bool _txConsole_OK() tx_nodiscard; bool _txConsole_Detach (bool activate); bool _txConsole_Draw (HDC dc); bool _txConsole_SetUnicodeFont(); const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra); HWND txCreateExtraWindow (CREATESTRUCT createData); HICON _txCreateTXIcon (int size) tx_nodiscard; int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL, int checkOfs = 0, const wchar_t checkLetters[2] = NULL); int _txPauseBeforeTermination (HWND canvas); int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard; void _txActivateWindow (HWND wnd, unsigned mode); int _txGetInput(); LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); const char* _txPlayVideo_FindVLC() tx_nodiscard; bool _txCreateShortcut (const char shortcutName[], const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL, const char description[] = NULL, int cmdShow = SW_SHOWNORMAL, const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0, COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD)); void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) tx_nodiscard; void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]); const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args); void _txOnTerminate(); void _txOnUnexpected(); void _txOnPureCall(); void _txOnNewHandlerAnsi(); int _txOnNewHandler (size_t size); void _txOnSignal (int signal = 0, int fpe = 0); BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type); void _txOnSecurityError (int code, void*); void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code); int _txOnMatherr (_exception* except); void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned line, uintptr_t); int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line); int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5); int _txOnErrorReport (int type, const char* text, int* ret); int tx_glGetError (int setError = INT_MIN); void _txOnCExit(); void _txOnExit (int retcode); void _txOnFatalExit (int retcode); void _txOnExitProcess (unsigned retcode); void _txOnFatalAppExitA (unsigned action, const char message[]); bool _txOnTerminateProcess (HANDLE process, unsigned retcode); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter); void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc); long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc); long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]); intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]); intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type); intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0, unsigned params = 0, const ULONG_PTR info[] = NULL); void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?", bool readSource = true); const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true, CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread()); int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL, HANDLE thread = GetCurrentThread()); const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false); const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2); bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL, Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL, const char** source = NULL, int context = 2); intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN); bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL); uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL, int useHotPatching = false, HMODULE module = NULL, bool debug = false); bool _txInDll() tx_nodiscard; PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard; bool _txKillProcess (DWORD pid); int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/); bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true); bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid()); IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard; bool _txIsConsoleSubsystem(); const char* _txAppInfo() tx_nodiscard; #if defined (_CLANG_VER) && !defined (_MSC_VER) void _txLibCppDebugFunction (std::__libcpp_debug_info const& info); #endif #endif // TX_COMPILED inline bool _txCanvas_OK () tx_nodiscard; int _txCanvas_SetRefreshLock (int count); const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0, const char msg[] = NULL, ...) tx_printfy (5); bool _txIsBadReadPtr (const void* address); intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3); intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg); bool _txIsTTY (int fd); void txReopenStdio(); #if defined (__CYGWIN__) int _getch(); int _putch (int ch); int _kbhit() tx_nodiscard; #endif //----------------------------------------------------------------------------------------------------------------- // There are macros for __FILE__ and __LINE__ to work properly. #if !defined (NDEBUG) #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \ (assert (cond), true) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Параметр \"%s\" неверен." \ " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка.", #dc), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (TX_ERROR ("\a" "%s" \ "Если вы указали параметр \"%s\", то он неверен.%s", \ (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \ #dc, \ ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка." : "")), 1) ) #else #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #endif //----------------------------------------------------------------------------------------------------------------- // Take action in debug configuration only. // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'( #if !defined (NDEBUG) #define _TX_ON_DEBUG( code ) { code; } #else #define _TX_ON_DEBUG( code ) ; #endif //----------------------------------------------------------------------------------------------------------------- // Invokes an error without location information. "$$" restores TX-related call location context #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__) //----------------------------------------------------------------------------------------------------------------- // Safe call of a function via its pointer #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 ) #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 ) //----------------------------------------------------------------------------------------------------------------- // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x. #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \ !(cond) && GetTickCount() < _t; \ Sleep (_txWindowUpdateInterval)) \ ; \ \ if (!(cond)) \ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); } //----------------------------------------------------------------------------------------------------------------- // Detouring in case of SEH mechanism #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 ) #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; } //----------------------------------------------------------------------------------------------------------------- // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code. #if defined (IN) // #undef IN #endif #if defined (OUT) // #undef OUT #endif //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal global data //! @name Внутренние глобальные данные // // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :) // // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же. // Здесь это сделано только в образовательных целях. // // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс. //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<< const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна _TX_IDM_CONSOLE = 40001, _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas //----------------------------------------------------------------------------------------------------------------- volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize(); volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main() volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT() RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0] HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP), // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock() UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question. int _txConsole = false; // Only first TXLib module in app can own the console bool _txMain = false; // First TXLib wnd opened (closing it terminates program) bool _txIsDll = false; // TXLib module is in DLL volatile bool _txRunning = false; // main() is still running volatile bool _txExit = false; // exit() is active volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE() volatile unsigned _txMouseButtons = 0; volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook(). _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro volatile int _txErrors = 0; // TX_ERROR calls sequental number volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError() volatile long _txSENumber = 0; // SEH exceptions sequental number volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess, (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA, (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp, (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier, (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler, (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace, (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize, (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions, (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64, (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr, (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup, (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64, (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64, (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64, (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext }; volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- extern volatile unsigned _txCanaryFirst; extern volatile unsigned _txCanaryLast; extern volatile HWND _txCanvas_Window; extern volatile unsigned _txCanvas_ThreadId; extern HDC _txCanvas_BackBuf[2]; extern RGBQUAD* _txCanvas_Pixels; extern volatile int _txCanvas_RefreshLock; extern volatile WNDPROC _txAltWndProc; extern volatile bool _txExit; extern volatile int _txOGLError; //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib engine init/check/cleanup //! @name Инициализация/проверка/завершение TXLib //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Early initialization //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize() { if (_txInitialized) return 1; _txInitialized = 1; #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585 #endif #if defined (_TX_ALLOW_TRACE) _txLocLvlSet (1); #endif _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" " "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n"); OutputDebugString ("\n")); _txMainThreadId = GetCurrentThreadId(); _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId); $3 _txIsDll = _txInDll(); $ if (!_txIsDll) { $ _txConsole = ! FindAtom ("_txConsole"); $ (void) AddAtom ("_txConsole"); //-V530 } $ if (_txConsole) { $ _txCheckSourceCP (_TX_CODEPAGE, true); $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ _txOnSignal(); $ if (!*_txLogName) {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); } $ if (!_txIsDll) { $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler)); $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter); } $ ::std::set_terminate (_txOnTerminate); $ ::std::set_new_handler (_txOnNewHandlerAnsi); $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected)); #if defined (_CLANG_VER) && !defined (_MSC_VER) $ ::std::__libcpp_debug_function = _txLibCppDebugFunction; #endif $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true); $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #if defined (_MSC_VER) $ _set_printf_count_output (1); $ _set_new_handler (_txOnNewHandler); $ _set_new_mode (1); #if !defined (_CLANG_VER) $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); $ _CrtSetAllocHook (_txOnAllocHook); $ unsigned mode = _CRTDBG_MODE_FILE; $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0; $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode); $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG); $ _set_abort_behavior (0, _CALL_REPORTFAULT); $ _RTC_SetErrorFunc (_txOnRTCFailure); $ _set_purecall_handler (_txOnPureCall); $ _set_invalid_parameter_handler (_txOnInvalidParam); #endif #if defined (__STDC_LIB_EXT1__) $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi); #endif #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386) $ __setusermatherr (_txOnMatherr); #endif #if !defined (__CYGWIN__) $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR); #endif $ HWND console = _txConsole_Attach(); $ SetWindowTextA (console, txGetModuleFileName (false)); } $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL"); $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL"); $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit); $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit); $ InitializeCriticalSection (&_txCanvas_LockBackBuf); $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted; $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted; $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted; $ Win32::DeleteDC (dc) asserted; $ atexit (_txCleanup); $ if (_txConsole) { $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ tx_fpreset(); $ srand ((unsigned) time (NULL)); //-V202 $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif } $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used" $ return 1; } //----------------------------------------------------------------------------------------------------------------- bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/) { $3 const char* sCodePage = NULL; $ int codePage = 0; $ switch (((unsigned const char*) "А") [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
6861  // ресурсов и системы сборки. Поэтому для независимости от них все будет строиться на этапе выполнения,
6862  // динамически. Вы еще гляньте, как это реализовано в txDialog::dialogBox() и функциях _tx_DLGTEMPLATE_()... О_о //------------------------------------------------------------------------------------------------------------- #define ID_TEXT_ 101 #define ID_INPUT_ 102 //------------------------------------------------------------------------------------------------------------- // Задание макета (вида) диалога в виде массива структур. // С помощью особого порядка полей в структуре txDialog::Layout и констант из класса txDialog этот массив // становится похож на описание ресурса диалога в .rc-файле. // См. описание синтаксиса rc-файла в документации по Win32 (MSDN, http://msdn.com). //------------------------------------------------------------------------------------------------------------- txDialog::Layout layout[] = //----------------------+----------+-----------+-----------------+--------------------------------------------- // Тип элемента | Имя | Иденти- | Координаты | Флаги элементов // диалога | элемента | фикатор |-----------------| (см. описание элементов // | | элемента | X | Y |Шир.|Выс.| окон диалога в MSDN) //----------------------+----------+-----------+---+---+----+----+--------------------------------------------- // | | | | | | | {{ txDialog::DIALOG, caption, 0, 0, 0, 240, 85 }, { txDialog::STATIC, text, ID_TEXT_, 10, 10, 150, 40, SS_LEFT }, { txDialog::EDIT, input, ID_INPUT_, 10, 60, 220, 15, ES_LEFT | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP }, { txDialog::BUTTON, "&OK", IDOK, 180, 10, 50, 15, BS_DEFPUSHBUTTON | WS_TABSTOP }, { txDialog::BUTTON, "&Cancel", IDCANCEL, 180, 30, 50, 15, BS_PUSHBUTTON | WS_TABSTOP }, { txDialog::END }}; //------------------------------------------------------------------------------------------------------------- // Класс диалога для InputBox. Внутренний, т.к. зачем ему быть внешним. // Нужен в основном для задания строки ввода (str) и оконной функции диалогового окна, требуемой Win32 (она // построена макросами TX_BEGIN_MESSAGE_MAP и другими). Можно не делать внутреннего класса, но тогда оконную // функцию придется писать в глобальной области видимости, и str объявлять глобально тоже (или передавать ее // адрес через DialogBoxParam и записывать его в класс во время обработки WM_INITDIALOG). //------------------------------------------------------------------------------------------------------------- struct inputDlg : txDialog { char str [1024]; //--------------------------------------------------------------------------------------------------------- inputDlg() : str() {} //--------------------------------------------------------------------------------------------------------- TX_BEGIN_MESSAGE_MAP() // Карта сообщений (на самом деле это начало оконной функции). //-V2525 TX_COMMAND_MAP // Здесь обрабатываются WM_COMMAND (на самом деле это оператор switch). //------------------------------------------------------------------------------------------------- // При нажатии кнопки OK копируем строку из поля ввода в нашу переменную str, т.к. после закрытия // диалога строка ввода умрет и текст уже из нее получить. // Этот макрос на самом деле превращается в case из оператора switch. // _wnd -- это параметр оконной функции, см. определение макроса TX_BEGIN_MESSAGE_MAP(). //------------------------------------------------------------------------------------------------- TX_HANDLE (IDOK) GetDlgItemText (_wnd, ID_INPUT_, str, sizeof (str) - 1); TX_END_MESSAGE_MAP //-V2522 //--------------------------------------------------------------------------------------------------------- // Конец внутреннего класса диалога //--------------------------------------------------------------------------------------------------------- }; //------------------------------------------------------------------------------------------------------------- // Убираем дефайны, чтобы потом не мешали. // От этого они получаются "локального действия", как будто у них была бы область видимости -- функция. На самом // деле это сделано вручную через #undef. Чтобы подчеркнуть их локальную природу, у них имена заканчиваются на _. // Такие дефайны потом не перекосячат весь код после того как, фактически, стали уже не нужны. //------------------------------------------------------------------------------------------------------------- #undef ID_TEXT_ #undef ID_INPUT_ //------------------------------------------------------------------------------------------------------------- // Это статический объект, потому что строка в нем должна жить после завершения функции. //------------------------------------------------------------------------------------------------------------- static inputDlg dlg; //------------------------------------------------------------------------------------------------------------- // Передаем layout и запускаем окно диалога //------------------------------------------------------------------------------------------------------------- dlg.dialogBox (layout); //------------------------------------------------------------------------------------------------------------- // Возвращаем адрес строки из статического объекта. Так можно делать, потому что статический объект не умрет // при выходе из функции и строка в нем, соответственно, тоже. Адрес нестатических переменных передавать // синтаксически можно, но ведет к серьезным ошибкам. //------------------------------------------------------------------------------------------------------------- return dlg.str; } #endif // TX_COMPILED //! @} //} //================================================================================================================= //} //================================================================================================================= //================================================================================================================= //{ TXLIB IMPLEMENTATION // Реализация функций библиотеки //================================================================================================================= //! @cond INTERNAL { //----------------------------------------------------------------------------------------------------------------- //{ The Includes //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< _TX_END_NAMESPACE //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch #pragma warning (disable: 4005) // 'name': macro redefinition #endif #if defined (__STRICT_ANSI__) && defined (__STRICT_ANSI__UNDEFINED) #undef __STRICT_ANSI__ #endif //----------------------------------------------------------------------------------------------------------------- #include <stdarg.h> #include <io.h> #include <fcntl.h> #include <process.h> #include <signal.h> #include <setjmp.h> #include <locale.h> #include <limits.h> #include <stdint.h> #include <map> #include <numeric> #include <exception> #include <stdexcept> #include <tlhelp32.h> #include <shellapi.h> #if defined (_GCC_VER) #include <shlobj.h> #include <cxxabi.h> #include <unwind.h> #endif #if defined (__CYGWIN__) #include <stdarg.h> #include <unistd.h> #include <termios.h> #endif #if defined (_MSC_VER) #include <new.h> #include <shlobj.h> #include <ntstatus.h> #include <crtdbg.h> #include <rtcapi.h> #include <dbghelp.h> #endif #if defined (_GCC_VER) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 #include <inttypes.h> #endif //----------------------------------------------------------------------------------------------------------------- #if defined (TX_USE_SPEAK) //-------------------------------------------------------------------------------------- #include <SAPI.h> // <== ЕСЛИ ЗДЕСЬ ОШИБКА, ТО У ВАС НЕТ ФАЙЛА SAPI.h. No SAPI.h file, TXLib isn't guilty :( #endif //-------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (pop) // MSVC: Restore max level #endif #if defined (__STRICT_ANSI__UNDEFINED) #define __STRICT_ANSI__ // Redefine back #endif //----------------------------------------------------------------------------------------------------------------- _TX_BEGIN_NAMESPACE #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //================================================================================================================= //{ DLL functions import, missing types definitions //! @name Импорт внешних библиотек, определение недостающих типов //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Some of structs, consts and interfaces aren't defined in MinGW some early headers. // Copied from Windows SDK 7.0a. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { #ifndef AC_SRC_ALPHA #define AC_SRC_ALPHA 0x01 #endif #ifndef SMTO_ERRORONEXIT #define SMTO_ERRORONEXIT 0x0020 #endif #ifndef NT_CONSOLE_PROPS_SIG #define NT_CONSOLE_PROPS_SIG 0xA0000002 #endif #ifndef NIIF_INFO #define NIIF_INFO 0x00000001 #define NIIF_WARNING 0x00000002 #define NIIF_ERROR 0x00000003 #endif #ifndef NIF_INFO #define NIF_STATE 0x00000008 #define NIF_INFO 0x00000010 #endif #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004 #endif #ifndef SYMOPT_CASE_INSENSITIVE #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_NO_PROMPTS 0x00080000 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 #define SYMOPT_FAVOR_COMPRESSED 0x00800000 #define SYMOPT_FLAT_DIRECTORY 0x00400000 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 #define SYMOPT_OVERWRITE 0x00100000 #define SYMOPT_DEBUG 0x80000000 #endif // SEH exception codes. For GCC, see http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 64-66. #ifndef STATUS_POSSIBLE_DEADLOCK #define STATUS_POSSIBLE_DEADLOCK 0xC0000194 #endif #ifndef STATUS_FLOAT_MULTIPLE_FAULTS #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4 #endif #ifndef STATUS_STACK_BUFFER_OVERRUN #define STATUS_STACK_BUFFER_OVERRUN 0xC0000409 #endif #ifndef STATUS_ASSERTION_FAILURE #define STATUS_ASSERTION_FAILURE 0xC0000420 #endif #ifndef STATUS_WX86_BREAKPOINT #define STATUS_WX86_BREAKPOINT 0x4000001F #endif #ifndef DBG_PRINTEXCEPTION_C #define DBG_PRINTEXCEPTION_C 0x40010006 // OutputDebugStringA() call #endif #ifndef DBG_PRINTEXCEPTION_WIDE_C #define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A // OutputDebugStringW() call #endif #ifndef DBG_THREAD_NAME #define DBG_THREAD_NAME 0x406D1388 #endif #define EXCEPTION_CPP_MSC 0xE06D7363 // '?msc' #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 0x19930520 // '?msc' version magic, see ehdata.h #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 0x19930521 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 0x19930522 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1 0x01994000 // '?msc' version magic #define EXCEPTION_CPP_GCC 0x20474343 // ' GCC' #define EXCEPTION_CPP_GCC_UNWIND 0x21474343 // '!GCC' #define EXCEPTION_CPP_GCC_FORCED 0x22474343 // '"GCC' #define EXCEPTION_CLR_FAILURE 0xE0434f4D // 'аCOM' #define EXCEPTION_CPP_BORLAND_BUILDER 0x0EEDFAE6 // Should never occur here #define EXCEPTION_CPP_BORLAND_DELPHI 0x0EEDFADE // Should never occur here #pragma pack (push, 1) struct CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; }; struct CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; }; struct CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; }; struct DATABLOCK_HEADER { DWORD cbSize; DWORD dwSignature; }; struct NT_CONSOLE_PROPS { DATABLOCK_HEADER dbh; WORD wFillAttribute; WORD wPopupFillAttribute; COORD dwScreenBufferSize; COORD dwWindowSize; COORD dwWindowOrigin; DWORD nFont; DWORD nInputBufferSize; COORD dwFontSize; UINT uFontFamily; UINT uFontWeight; WCHAR FaceName[LF_FACESIZE]; UINT uCursorSize; BOOL bFullScreen; BOOL bQuickEdit; BOOL bInsertMode; BOOL bAutoPosition; UINT uHistoryBufferSize; UINT uNumberOfHistoryBuffers; BOOL bHistoryNoDup; COLORREF ColorTable[16]; }; struct FLASHWINFO { UINT cbSize; HWND hwnd; DWORD dwFlags; UINT uCount; DWORD dwTimeout; }; enum TBPFLAG { TBPF_NOPROGRESS = 0x0, TBPF_INDETERMINATE = 0x1, TBPF_NORMAL = 0x2, TBPF_ERROR = 0x4, TBPF_PAUSED = 0x8 }; #pragma pack (pop) const GUID IID_IShellLink = {0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_IShellLinkDataList = {0x45e2b4ae, 0xb1c3, 0x11d0, {0xb9,0x2f,0x00,0xa0,0xc9,0x03,0x12,0xe1}}; const GUID IID_IPersistFile = {0x0000010b, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; const GUID CLSID_TaskbarList = {0x56fdf344, 0xfd6d, 0x11d0, {0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}}; const GUID CLSID_SpVoice = {0x96749377, 0x3391, 0x11d2, {0x9e,0xe3,0x00,0xc0,0x4f,0x79,0x73,0x96}}; const GUID IID_ISpVoice = {0x6c44df74, 0x72b9, 0x4992, {0xa1,0xec,0xef,0x99,0x6e,0x04,0x22,0xd4}}; typedef DWORD NTSTATUS; typedef ULONG_PTR KAFFINITY; typedef LONG KPRIORITY; struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; wchar_t* Buffer; }; struct RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; UNICODE_STRING DosPath; }; struct CURDIR { UNICODE_STRING DosPath; void* Handle; }; struct RTL_USER_PROCESS_PARAMETERS { ULONG AllocationSize; ULONG Size; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; CURDIR CurrentDirectory; UNICODE_STRING DllPath; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; wchar_t* Environment; ULONG dwX; ULONG dwY; ULONG dwXSize; ULONG dwYSize; ULONG dwXCountChars; ULONG dwYCountChars; ULONG dwFillAttribute; ULONG dwFlags; ULONG wShowWindow; UNICODE_STRING WindowTitle; UNICODE_STRING Desktop; UNICODE_STRING ShellInfo; UNICODE_STRING RuntimeInfo; RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; }; struct PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; void* Reserved3[2]; void* Ldr; RTL_USER_PROCESS_PARAMETERS* ProcessParameters; void* Reserved4[3]; void* AtlThunkSListPtr; void* Reserved5; ULONG Reserved6; void* Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; void* Reserved9[45]; BYTE Reserved10[96]; void* PostProcessInitRoutine; BYTE Reserved11[128]; void* Reserved12[1]; ULONG SessionId; }; struct TEB { void* Reserved1[12]; PEB* ProcessEnvironmentBlock; void* Reserved2[399]; BYTE Reserved3[1952]; void* TlsSlots[64]; BYTE Reserved4[8]; void* Reserved5[26]; void* ReservedForOle; void* Reserved6[4]; void* TlsExpansionSlots; }; struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PEB* PebBaseAddress; KAFFINITY AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; }; enum ADDRESS_MODE { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat }; struct ADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; }; struct KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64 Reserved[5]; }; struct STACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; void* FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; }; struct WOW64_FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE RegisterArea[80]; DWORD Cr0NpxState; }; #pragma pack (push, 4) struct WOW64_CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; WOW64_FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[512]; }; #pragma pack (pop) struct SYMBOL_INFO { ULONG SizeOfStruct; ULONG TypeIndex; ULONG64 Reserved[2]; ULONG info; ULONG Size; ULONG64 ModBase; ULONG Flags; ULONG64 Value; ULONG64 Address; ULONG Register; ULONG Scope; ULONG Tag; ULONG NameLen; ULONG MaxNameLen; char Name[1]; }; struct IMAGEHLP_LINE64 { DWORD SizeOfStruct; void* Key; DWORD LineNumber; char* FileName; DWORD64 Address; }; typedef bool (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64) (HANDLE process, DWORD64 baseAddress, void* buffer, DWORD size, DWORD* bytesRead); typedef void* (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64) (HANDLE process, DWORD64 baseAddress); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64) (HANDLE process, DWORD64 address); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64) (HANDLE process, HANDLE thread, ADDRESS64* address); typedef void (*unexpected_handler)(); #pragma pack (push, 4) struct MINIDUMP_THREAD_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; }; struct MINIDUMP_THREAD_EX_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; ULONG64 BackingStoreBase; ULONG64 BackingStoreEnd; }; struct MINIDUMP_MODULE_CALLBACK { wchar_t* FullPath; ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; VS_FIXEDFILEINFO VersionInfo; void* CvRecord; ULONG SizeOfCvRecord; void* MiscRecord; ULONG SizeOfMiscRecord; }; struct MINIDUMP_INCLUDE_THREAD_CALLBACK { ULONG ThreadId; }; struct MINIDUMP_INCLUDE_MODULE_CALLBACK { ULONG64 BaseOfImage; }; struct MINIDUMP_MEMORY_INFO { ULONG64 BaseAddress; ULONG64 AllocationBase; ULONG32 AllocationProtect; ULONG32 __alignment1; ULONG64 RegionSize; ULONG32 State; ULONG32 Protect; ULONG32 Type; ULONG32 __alignment2; }; struct MINIDUMP_USER_STREAM { ULONG32 Type; ULONG BufferSize; void* Buffer; }; struct MINIDUMP_USER_STREAM_INFORMATION { ULONG UserStreamCount; MINIDUMP_USER_STREAM* UserStreamArray; }; struct MINIDUMP_CALLBACK_INPUT { ULONG ProcessId; HANDLE ProcessHandle; ULONG CallbackType; union //-V2514 { MINIDUMP_THREAD_CALLBACK Thread; MINIDUMP_THREAD_EX_CALLBACK ThreadEx; MINIDUMP_MODULE_CALLBACK Module; MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; }; }; struct MINIDUMP_CALLBACK_OUTPUT { union //-V2514 { ULONG ModuleWriteFlags; ULONG ThreadWriteFlags; ULONG SecondaryFlags; struct { ULONG64 MemoryBase; ULONG MemorySize; }; struct { unsigned CheckCancel; unsigned Cancel; }; HANDLE Handle; //-V117 }; struct { MINIDUMP_MEMORY_INFO VmRegion; unsigned Continue; }; HRESULT Status; }; struct MINIDUMP_EXCEPTION_INFORMATION { DWORD ThreadId; EXCEPTION_POINTERS* ExceptionPointers; unsigned ClientPointers; }; typedef int (WINAPI* MINIDUMP_CALLBACK_ROUTINE) (void* param, MINIDUMP_CALLBACK_INPUT* input, MINIDUMP_CALLBACK_OUTPUT* output); struct MINIDUMP_CALLBACK_INFORMATION { MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; void* CallbackParam; }; enum MINIDUMP_TYPE { MiniDumpNormal = 0x00000000, MiniDumpWithDataSegs = 0x00000001, MiniDumpWithFullMemory = 0x00000002, MiniDumpWithHandleData = 0x00000004, MiniDumpFilterMemory = 0x00000008, MiniDumpScanMemory = 0x00000010, MiniDumpWithUnloadedModules = 0x00000020, MiniDumpWithIndirectlyReferencedMemory = 0x00000040, MiniDumpFilterModulePaths = 0x00000080, MiniDumpWithProcessThreadData = 0x00000100, MiniDumpWithPrivateReadWriteMemory = 0x00000200, MiniDumpWithoutOptionalData = 0x00000400, MiniDumpWithFullMemoryInfo = 0x00000800, MiniDumpWithThreadInfo = 0x00001000, MiniDumpWithCodeSegs = 0x00002000, MiniDumpWithoutAuxiliaryState = 0x00004000, MiniDumpWithFullAuxiliaryState = 0x00008000, MiniDumpWithPrivateWriteCopyMemory = 0x00010000, MiniDumpIgnoreInaccessibleMemory = 0x00020000, MiniDumpWithTokenInformation = 0x00040000 }; #ifndef CONTEXT_ALL #define CONTEXT_ALL ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS ) #endif #pragma pack (pop) } // namespace Win32 #endif // TX_COMPILED #define FOREGROUND_BLACK ( 0 ) #define FOREGROUND_CYAN ( FOREGROUND_BLUE | FOREGROUND_GREEN ) #define FOREGROUND_MAGENTA ( FOREGROUND_BLUE | FOREGROUND_RED ) #define FOREGROUND_DARKYELLOW ( FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_LIGHTGRAY ( FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_DARKGRAY ( FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTBLUE ( FOREGROUND_BLUE | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTGREEN ( FOREGROUND_GREEN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTCYAN ( FOREGROUND_CYAN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTRED ( FOREGROUND_RED | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTMAGENTA ( FOREGROUND_MAGENTA | FOREGROUND_INTENSITY ) #define FOREGROUND_YELLOW ( FOREGROUND_DARKYELLOW | FOREGROUND_INTENSITY ) #define FOREGROUND_WHITE ( FOREGROUND_LIGHTGRAY | FOREGROUND_INTENSITY ) #define BACKGROUND_BLACK ( 0 ) #define BACKGROUND_CYAN ( BACKGROUND_BLUE | BACKGROUND_GREEN ) #define BACKGROUND_MAGENTA ( BACKGROUND_BLUE | BACKGROUND_RED ) #define BACKGROUND_DARKYELLOW ( BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_GRAY ( BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_DARKGRAY ( BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTBLUE ( BACKGROUND_BLUE | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTGREEN ( BACKGROUND_GREEN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTCYAN ( BACKGROUND_CYAN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTRED ( BACKGROUND_RED | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTMAGENTA ( BACKGROUND_MAGENTA | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTYELLOW ( BACKGROUND_DARKYELLOW | BACKGROUND_INTENSITY ) #define BACKGROUND_WHITE ( BACKGROUND_DARKGRAY | BACKGROUND_INTENSITY ) //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ There are copies of MSVC compiler built-in predefined definitions, which are wrong in 64-bit mode. // So we have to override them. See: http://stackoverflow.com/questions/39113168 //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< #if defined (_MSC_VER) // MS ABI C++ Exception Layout namespace Win32 { // --------------------------- // #pragma pack (push, 4) // EXCEPTION_RECORD: // +==================================================+ struct ThrowInfo // |... | { // |NumberParameters: 3, 4 or more | __int32 attributes; // |ExceptionInformation[0]: MS signature 0x19930520 | __int32 pmfnUnwind; // |ExceptionInformation[1]: object* thrown | __int32 pForwardCompat; // |ExceptionInformation[2]: ThrowInfo* --------------+---+ __int32 pCatchableTypeArray; // |ExceptionInformation[3]: ImageBase (if params > 3)| | }; // +==================================================+ | // | struct CatchableTypeArray // ThrowInfo: | { // +======================================+ <-------+ __int32 nCatchableTypes; // | ... | __int32 arrayOfCatchableTypes[]; // +-----+-- pCatchableTypeArray (ptr/RVA) | }; // | +======================================+ // | struct CatchableType // | CatchableTypeArray: { // +---> +======================================+ __int32 properties; // | ... | __int32 pType; // +-----+-- arrayOfCatchableTypes[0] (ptr/RVA) | __int32 thisDisplacement[3]; // struct _PMD // | +======================================+ __int32 sizeOrOffset; // | __int32 copyFunction; // | CatchableType: }; // +---> +====================+ // | ... | std::type_info: #pragma pack (pop) // | pType (ptr/RVA) ---+------> +==================+ // | ... | |type_info data | } // namespace Win32 // +====================+ |... | // +==================+ #endif // Similar to __CxxDetectRethrow(), see C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\crtsrc\vcruntime\frame.cpp: #define _TX_MSC__CXX_DETECT_RETHROW( exc ) \ ( \ (exc) && \ (exc) -> ExceptionCode == EXCEPTION_CPP_MSC && \ (exc) -> NumberParameters >= 3 && \ \ ((exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3) && \ \ (exc) -> ExceptionInformation[2] == 0 \ ) #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ The corresponding structures for GCC // // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h // See: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi //----------------------------------------------------------------------------------------------------------------- #if defined (_GCC_VER) #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // GCC ABI C++ Exception layout. A/B are ExceptionInformation[0]. namespace ABI { // -------------------------------------------------------------- // struct __cxa_exception // Case A: "_Unwind_Exception* A" is undependent exception: { // -------------------------------------------------------- union { // struct // __cxa_exception: std::type_info: { // -*--+====================+ +==================+ ::std::type_info* exceptionType; // ^ |exceptionType* -----+---->|type_info data | void (*exceptionDestructor)(void*); // | |... | |... | }; // -1 | | +==================+ struct // | | | { // A >----|--+--------------------+ __cxa_exception* primaryException; // | | |unwindHeader | void (*padding)(); // +1 | | | }; // | | | | }; // V | | | // -*--- +====================+ void (*unexpected_handler)(); // |object | std::terminate_handler terminateHandler; // +--------------------+ // __cxa_exception* nextException; // Case B: "_Unwind_Exception* B" is dependent exception int handlerCount; // (unwindHeader.exception_class & 1 != 0): int handlerSwitchValue; // ----------------------------------------------------- const unsigned char* actionRecord; // const unsigned char* languageSpecificData; // __cxa_exception: __cxa_exception: void* catchTemp; // -*--+====================+ -*--+=================+ void* adjustedPtr; // ^ |primaryException* --+-- ^ |exceptionType* | // | |... | \ | |... | _Unwind_Exception unwindHeader; // -1 | | | | | | }; // | | | | | | | // B >----|--+--------------------+ | -1 +-----------------+ struct __cxa_eh_globals // | | |unwindHeader | | | |unwindHeader | { // +1 | | | | | | | __cxa_exception* caughtExceptions; // | | | | | | | | unsigned int uncaughtExceptions; // V | | | \ | | | }; // -*--- +====================+ -->*--+=================+ // |... | |object | } // namespace ABI // . . | | // +-----------------+ extern "C" ABI::__cxa_eh_globals* __cxa_get_globals(); #endif // TX_COMPILED #endif //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Hand-made IAT. // Some IDEs don't link with these libs by default in console projects, so do sunrise by hand. :( //----------------------------------------------------------------------------------------------------------------- // Hand-made DLLIMPORT helpers #define _TX_DLLIMPORT( lib, retval, name, params ) TX_DLLIMPORT (true, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_OPT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_CRT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, please) void (*_txDllImport (const char dllFileName[], const char funcName[], bool required = true)) (); //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { _TX_DLLIMPORT ("GDI32", HDC, CreateCompatibleDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateCompatibleBitmap, (HDC dc, int width, int height)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetStockObject, (int object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, SelectObject, (HDC dc, HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetCurrentObject, (HDC dc, unsigned objectType)); _TX_DLLIMPORT ("GDI32", int, GetObjectA, (HGDIOBJ obj, int bufsize, void* buffer)); _TX_DLLIMPORT ("GDI32", DWORD, GetObjectType, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", bool, DeleteDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", bool, DeleteObject, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", COLORREF, SetTextColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, SetBkColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", int, SetBkMode, (HDC dc, int bkMode)); _TX_DLLIMPORT ("GDI32", HFONT, CreateFontA, (int height, int width, int escapement, int orientation, int weight, DWORD italic, DWORD underline, DWORD strikeout, DWORD charSet, DWORD outputPrec, DWORD clipPrec, DWORD quality, DWORD pitchAndFamily, const char face[])); _TX_DLLIMPORT ("GDI32", int, EnumFontFamiliesExA, (HDC dc, LPLOGFONT logFont, FONTENUMPROC enumProc, LPARAM lParam, DWORD reserved)); _TX_DLLIMPORT ("GDI32", COLORREF, SetPixel, (HDC dc, int x, int y, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, GetPixel, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", HPEN, CreatePen, (int penStyle, int width, COLORREF color)); _TX_DLLIMPORT ("GDI32", HBRUSH, CreateSolidBrush, (COLORREF color)); _TX_DLLIMPORT ("GDI32", bool, MoveToEx, (HDC dc, int x, int y, POINT* point)); _TX_DLLIMPORT ("GDI32", bool, LineTo, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", bool, Polygon, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Polyline, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, PolyBezier, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Rectangle, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, RoundRect, (HDC dc, int x0, int y0, int x1, int y1, int sizeX, int sizeY)); _TX_DLLIMPORT ("GDI32", bool, Ellipse, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, Arc, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Pie, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Chord, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, TextOutA, (HDC dc, int x, int y, const char string[], int length)); _TX_DLLIMPORT ("GDI32", UINT, SetTextAlign, (HDC dc, unsigned mode)); _TX_DLLIMPORT ("GDI32", bool, GetTextExtentPoint32A, (HDC dc, const char string[], int length, SIZE* size)); _TX_DLLIMPORT ("GDI32", bool, ExtFloodFill, (HDC dc, int x, int y, COLORREF color, unsigned type)); _TX_DLLIMPORT ("GDI32", bool, BitBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, StretchBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, PlgBlt, (HDC dest, const POINT* parallelogram, HDC src, int xSrc, int ySrc, int width, int height, HBITMAP mask, int xMask, int yMask)); _TX_DLLIMPORT ("GDI32", int, SetDIBitsToDevice, (HDC dc, int xDest, int yDest, DWORD width, DWORD height, int xSrc, int ySrc, unsigned startLine, unsigned numLines, const void* data, const BITMAPINFO* info, unsigned colorUse)); _TX_DLLIMPORT ("GDI32", int, GetDIBits, (HDC hdc, HBITMAP hbmp, unsigned uStartScan, unsigned cScanLines, void* lpvBits, BITMAPINFO* lpbi, unsigned usage)); _TX_DLLIMPORT ("GDI32", bool, PatBlt, (HDC dc, int x0, int y0, int width, int height, DWORD rOp)); _TX_DLLIMPORT ("GDI32", int, SetROP2, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", int, SetStretchBltMode, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", DWORD, GdiSetBatchLimit, (DWORD limit)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateDIBSection, (HDC dc, const BITMAPINFO* bmInfo, unsigned colorUsage, void **vBits, HANDLE section, DWORD offset)); _TX_DLLIMPORT ("User32", int, DrawTextA, (HDC dc, const char text[], int length, RECT* rect, unsigned format)); _TX_DLLIMPORT ("User32", HANDLE, LoadImageA, (HINSTANCE inst, const char name[], unsigned type, int sizex, int sizey, unsigned mode)); _TX_DLLIMPORT_OPT ("User32", bool, IsHungAppWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", HWND, GhostWindowFromHungWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", bool, FlashWindowEx, (const FLASHWINFO* flash)); _TX_DLLIMPORT ("WinMM", bool, PlaySound, (const char sound[], HMODULE mod, DWORD mode)); _TX_DLLIMPORT_OPT ("MSImg32", bool, TransparentBlt, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, unsigned transparentColor)); _TX_DLLIMPORT_OPT ("MSImg32", bool, AlphaBlend, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, BLENDFUNCTION blending)); _TX_DLLIMPORT ("Kernel32", void, ExitProcess, (unsigned retcode)); _TX_DLLIMPORT ("Kernel32", bool, TerminateProcess, (HANDLE process, unsigned retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalExit, (int retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalAppExitA, (unsigned action, const char message[])); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetThreadId, (HANDLE thread)); _TX_DLLIMPORT ("Kernel32", HWND, GetConsoleWindow, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetConsoleFont, (HANDLE con, DWORD fontIndex)); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetNumberOfConsoleFonts, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFont, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFO* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", void, RtlCaptureContext, (CONTEXT* contextRecord)); _TX_DLLIMPORT_OPT ("Kernel32", USHORT, RtlCaptureStackBackTrace, (DWORD framesToSkip, DWORD framesToCapture, void** backTrace, DWORD* hash)); _TX_DLLIMPORT_OPT ("Kernel32", void*, AddVectoredExceptionHandler, (unsigned long firstHandler, PVECTORED_EXCEPTION_HANDLER handler)); _TX_DLLIMPORT_OPT ("Kernel32", unsigned, RemoveVectoredExceptionHandler,(void* handler)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetModuleHandleEx, (DWORD flags, const char moduleName[], HMODULE* module)); _TX_DLLIMPORT_OPT ("Kernel32", bool, IsWow64Process, (HANDLE process, int* isWow64Process)); _TX_DLLIMPORT_OPT ("Kernel32", bool, Wow64GetThreadContext, (HANDLE thread, WOW64_CONTEXT* context)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetThreadStackGuarantee, (unsigned long* stackSize)); _TX_DLLIMPORT ("OLE32", HRESULT, CoInitialize, (void*)); _TX_DLLIMPORT ("OLE32", HRESULT, CoCreateInstance, (REFCLSID clsId, IUnknown*, DWORD, REFIID iId, void** value)); _TX_DLLIMPORT ("OLE32", void, CoUninitialize, (void)); _TX_DLLIMPORT ("Shell32", HINSTANCE,ShellExecuteA, (HWND wnd, const char operation[], const char file[], const char parameters[], const char directory[], int showCmd)); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIA, (const char string[], const char search[])); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIW, (const wchar_t string[], const wchar_t search[])); _TX_DLLIMPORT_OPT ("NTDLL", char*, wine_get_version, (void)); _TX_DLLIMPORT ("NTDLL", NTSTATUS, NtQueryInformationProcess, (HANDLE process, int infoClass, void* processInfo, unsigned long szProcessInfo, unsigned long* szReturnInfo)); _TX_DLLIMPORT_CRT ("MSVCRT", void, exit, (int retcode)); _TX_DLLIMPORT_CRT ("MSVCRT", void, _cexit, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _fpreset, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _controlfp, (unsigned control, unsigned mask)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthread, (void (__cdecl* start_address) (void*), unsigned stack_size, void* arglist)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthreadex, (void* security, unsigned stack_size, unsigned (__stdcall* start_address) (void*), void *arglist, unsigned init_flag, unsigned* thread_addr)); _TX_DLLIMPORT_CRT ("MSVCRT", char*, __unDName, (char* outStr, const char* mangledName, int outStrLen, void* (*mallocFunc) (size_t size), void (*freeFunc) (void *pointer), unsigned short flags)); _TX_DLLIMPORT_CRT ("MSVCRT", unexpected_handler, set_unexpected, (unexpected_handler handler)); _TX_DLLIMPORT_OPT ("OpenGL32", HDC, wglGetCurrentDC, (void)); _TX_DLLIMPORT_OPT ("OpenGL32", unsigned, glGetError, (void)); _TX_DLLIMPORT_OPT ("Glu32", const char*, gluErrorString, (unsigned error)); _TX_DLLIMPORT_OPT ("ComDlg32", DWORD, CommDlgExtendedError, (void)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, MiniDumpWriteDump, (HANDLE process, DWORD processId, HANDLE file, MINIDUMP_TYPE dumpType, MINIDUMP_EXCEPTION_INFORMATION* exceptionParam, MINIDUMP_USER_STREAM_INFORMATION* userStreamParam, MINIDUMP_CALLBACK_INFORMATION* callbackParam)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("DbgHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); namespace MinGW { _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("MgwHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); } // namespace MinGW } // namespace Win32 #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal function prototypes, macros and constants // @name Прототипы внутренних функций, макросы и константы //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize(); void _txCleanup(); HWND _txCanvas_CreateWindow (const SIZE* size); bool _txCanvas_OnCREATE (HWND wnd); bool _txCanvas_OnDESTROY (HWND wnd); bool _txCanvas_OnCLOSE (HWND); bool _txCanvas_OnPAINT (HWND wnd); bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down); bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info); bool _txCanvas_OnTIMER (HWND wnd, WPARAM id); bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords); bool _txCanvas_OnMOUSELEAVE (HWND wnd); bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd); bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd); unsigned WINAPI _txCanvas_ThreadProc (void* data); LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard; bool _txBuffer_Delete (HDC* dc); bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC()); HWND _txConsole_Attach(); bool _txConsole_OK() tx_nodiscard; bool _txConsole_Detach (bool activate); bool _txConsole_Draw (HDC dc); bool _txConsole_SetUnicodeFont(); const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra); HWND txCreateExtraWindow (CREATESTRUCT createData); HICON _txCreateTXIcon (int size) tx_nodiscard; int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL, int checkOfs = 0, const wchar_t checkLetters[2] = NULL); int _txPauseBeforeTermination (HWND canvas); int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard; void _txActivateWindow (HWND wnd, unsigned mode); int _txGetInput(); LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); const char* _txPlayVideo_FindVLC() tx_nodiscard; bool _txCreateShortcut (const char shortcutName[], const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL, const char description[] = NULL, int cmdShow = SW_SHOWNORMAL, const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0, COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD)); void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) tx_nodiscard; void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]); const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args); void _txOnTerminate(); void _txOnUnexpected(); void _txOnPureCall(); void _txOnNewHandlerAnsi(); int _txOnNewHandler (size_t size); void _txOnSignal (int signal = 0, int fpe = 0); BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type); void _txOnSecurityError (int code, void*); void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code); int _txOnMatherr (_exception* except); void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned line, uintptr_t); int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line); int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5); int _txOnErrorReport (int type, const char* text, int* ret); int tx_glGetError (int setError = INT_MIN); void _txOnCExit(); void _txOnExit (int retcode); void _txOnFatalExit (int retcode); void _txOnExitProcess (unsigned retcode); void _txOnFatalAppExitA (unsigned action, const char message[]); bool _txOnTerminateProcess (HANDLE process, unsigned retcode); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter); void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc); long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc); long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]); intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]); intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type); intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0, unsigned params = 0, const ULONG_PTR info[] = NULL); void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?", bool readSource = true); const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true, CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread()); int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL, HANDLE thread = GetCurrentThread()); const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false); const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2); bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL, Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL, const char** source = NULL, int context = 2); intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN); bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL); uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL, int useHotPatching = false, HMODULE module = NULL, bool debug = false); bool _txInDll() tx_nodiscard; PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard; bool _txKillProcess (DWORD pid); int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/); bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true); bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid()); IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard; bool _txIsConsoleSubsystem(); const char* _txAppInfo() tx_nodiscard; #if defined (_CLANG_VER) && !defined (_MSC_VER) void _txLibCppDebugFunction (std::__libcpp_debug_info const& info); #endif #endif // TX_COMPILED inline bool _txCanvas_OK () tx_nodiscard; int _txCanvas_SetRefreshLock (int count); const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0, const char msg[] = NULL, ...) tx_printfy (5); bool _txIsBadReadPtr (const void* address); intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3); intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg); bool _txIsTTY (int fd); void txReopenStdio(); #if defined (__CYGWIN__) int _getch(); int _putch (int ch); int _kbhit() tx_nodiscard; #endif //----------------------------------------------------------------------------------------------------------------- // There are macros for __FILE__ and __LINE__ to work properly. #if !defined (NDEBUG) #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \ (assert (cond), true) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Параметр \"%s\" неверен." \ " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка.", #dc), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (TX_ERROR ("\a" "%s" \ "Если вы указали параметр \"%s\", то он неверен.%s", \ (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \ #dc, \ ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка." : "")), 1) ) #else #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #endif //----------------------------------------------------------------------------------------------------------------- // Take action in debug configuration only. // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'( #if !defined (NDEBUG) #define _TX_ON_DEBUG( code ) { code; } #else #define _TX_ON_DEBUG( code ) ; #endif //----------------------------------------------------------------------------------------------------------------- // Invokes an error without location information. "$$" restores TX-related call location context #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__) //----------------------------------------------------------------------------------------------------------------- // Safe call of a function via its pointer #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 ) #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 ) //----------------------------------------------------------------------------------------------------------------- // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x. #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \ !(cond) && GetTickCount() < _t; \ Sleep (_txWindowUpdateInterval)) \ ; \ \ if (!(cond)) \ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); } //----------------------------------------------------------------------------------------------------------------- // Detouring in case of SEH mechanism #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 ) #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; } //----------------------------------------------------------------------------------------------------------------- // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code. #if defined (IN) // #undef IN #endif #if defined (OUT) // #undef OUT #endif //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal global data //! @name Внутренние глобальные данные // // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :) // // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же. // Здесь это сделано только в образовательных целях. // // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс. //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<< const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна _TX_IDM_CONSOLE = 40001, _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas //----------------------------------------------------------------------------------------------------------------- volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize(); volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main() volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT() RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0] HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP), // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock() UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question. int _txConsole = false; // Only first TXLib module in app can own the console bool _txMain = false; // First TXLib wnd opened (closing it terminates program) bool _txIsDll = false; // TXLib module is in DLL volatile bool _txRunning = false; // main() is still running volatile bool _txExit = false; // exit() is active volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE() volatile unsigned _txMouseButtons = 0; volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook(). _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro volatile int _txErrors = 0; // TX_ERROR calls sequental number volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError() volatile long _txSENumber = 0; // SEH exceptions sequental number volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess, (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA, (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp, (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier, (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler, (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace, (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize, (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions, (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64, (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr, (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup, (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64, (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64, (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64, (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext }; volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- extern volatile unsigned _txCanaryFirst; extern volatile unsigned _txCanaryLast; extern volatile HWND _txCanvas_Window; extern volatile unsigned _txCanvas_ThreadId; extern HDC _txCanvas_BackBuf[2]; extern RGBQUAD* _txCanvas_Pixels; extern volatile int _txCanvas_RefreshLock; extern volatile WNDPROC _txAltWndProc; extern volatile bool _txExit; extern volatile int _txOGLError; //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib engine init/check/cleanup //! @name Инициализация/проверка/завершение TXLib //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Early initialization //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize() { if (_txInitialized) return 1; _txInitialized = 1; #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585 #endif #if defined (_TX_ALLOW_TRACE) _txLocLvlSet (1); #endif _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" " "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n"); OutputDebugString ("\n")); _txMainThreadId = GetCurrentThreadId(); _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId); $3 _txIsDll = _txInDll(); $ if (!_txIsDll) { $ _txConsole = ! FindAtom ("_txConsole"); $ (void) AddAtom ("_txConsole"); //-V530 } $ if (_txConsole) { $ _txCheckSourceCP (_TX_CODEPAGE, true); $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ _txOnSignal(); $ if (!*_txLogName) {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); } $ if (!_txIsDll) { $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler)); $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter); } $ ::std::set_terminate (_txOnTerminate); $ ::std::set_new_handler (_txOnNewHandlerAnsi); $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected)); #if defined (_CLANG_VER) && !defined (_MSC_VER) $ ::std::__libcpp_debug_function = _txLibCppDebugFunction; #endif $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true); $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #if defined (_MSC_VER) $ _set_printf_count_output (1); $ _set_new_handler (_txOnNewHandler); $ _set_new_mode (1); #if !defined (_CLANG_VER) $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); $ _CrtSetAllocHook (_txOnAllocHook); $ unsigned mode = _CRTDBG_MODE_FILE; $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0; $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode); $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG); $ _set_abort_behavior (0, _CALL_REPORTFAULT); $ _RTC_SetErrorFunc (_txOnRTCFailure); $ _set_purecall_handler (_txOnPureCall); $ _set_invalid_parameter_handler (_txOnInvalidParam); #endif #if defined (__STDC_LIB_EXT1__) $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi); #endif #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386) $ __setusermatherr (_txOnMatherr); #endif #if !defined (__CYGWIN__) $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR); #endif $ HWND console = _txConsole_Attach(); $ SetWindowTextA (console, txGetModuleFileName (false)); } $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL"); $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL"); $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit); $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit); $ InitializeCriticalSection (&_txCanvas_LockBackBuf); $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted; $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted; $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted; $ Win32::DeleteDC (dc) asserted; $ atexit (_txCleanup); $ if (_txConsole) { $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ tx_fpreset(); $ srand ((unsigned) time (NULL)); //-V202 $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif } $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used" $ return 1; } //----------------------------------------------------------------------------------------------------------------- bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/) { $3 const char* sCodePage = NULL; $ int codePage = 0; $ switch (((unsigned const char*) "А") [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
6863  //-------------------------------------------------------------------------------------------------------------
6864 
6865  #define ID_TEXT_ 101
6866  #define ID_INPUT_ 102
6867 
6868  //-------------------------------------------------------------------------------------------------------------
6869  // Задание макета (вида) диалога в виде массива структур.
6870  // С помощью особого порядка полей в структуре txDialog::Layout и констант из класса txDialog этот массив
6871  // становится похож на описание ресурса диалога в .rc-файле.
6872  // См. описание синтаксиса rc-файла в документации по Win32 (MSDN, http://msdn.com).
6873  //-------------------------------------------------------------------------------------------------------------
6874 
6875  txDialog::Layout layout[] =
6876 
6877  //----------------------+----------+-----------+-----------------+---------------------------------------------
6878  // Тип элемента | Имя | Иденти- | Координаты | Флаги элементов // диалога | элемента | фикатор |-----------------| (см. описание элементов // | | элемента | X | Y |Шир.|Выс.| окон диалога в MSDN) //----------------------+----------+-----------+---+---+----+----+--------------------------------------------- // | | | | | | | {{ txDialog::DIALOG, caption, 0, 0, 0, 240, 85 }, { txDialog::STATIC, text, ID_TEXT_, 10, 10, 150, 40, SS_LEFT }, { txDialog::EDIT, input, ID_INPUT_, 10, 60, 220, 15, ES_LEFT | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP }, { txDialog::BUTTON, "&OK", IDOK, 180, 10, 50, 15, BS_DEFPUSHBUTTON | WS_TABSTOP }, { txDialog::BUTTON, "&Cancel", IDCANCEL, 180, 30, 50, 15, BS_PUSHBUTTON | WS_TABSTOP }, { txDialog::END }}; //------------------------------------------------------------------------------------------------------------- // Класс диалога для InputBox. Внутренний, т.к. зачем ему быть внешним. // Нужен в основном для задания строки ввода (str) и оконной функции диалогового окна, требуемой Win32 (она // построена макросами TX_BEGIN_MESSAGE_MAP и другими). Можно не делать внутреннего класса, но тогда оконную // функцию придется писать в глобальной области видимости, и str объявлять глобально тоже (или передавать ее // адрес через DialogBoxParam и записывать его в класс во время обработки WM_INITDIALOG). //------------------------------------------------------------------------------------------------------------- struct inputDlg : txDialog { char str [1024]; //--------------------------------------------------------------------------------------------------------- inputDlg() : str() {} //--------------------------------------------------------------------------------------------------------- TX_BEGIN_MESSAGE_MAP() // Карта сообщений (на самом деле это начало оконной функции). //-V2525 TX_COMMAND_MAP // Здесь обрабатываются WM_COMMAND (на самом деле это оператор switch). //------------------------------------------------------------------------------------------------- // При нажатии кнопки OK копируем строку из поля ввода в нашу переменную str, т.к. после закрытия // диалога строка ввода умрет и текст уже из нее получить. // Этот макрос на самом деле превращается в case из оператора switch. // _wnd -- это параметр оконной функции, см. определение макроса TX_BEGIN_MESSAGE_MAP(). //------------------------------------------------------------------------------------------------- TX_HANDLE (IDOK) GetDlgItemText (_wnd, ID_INPUT_, str, sizeof (str) - 1); TX_END_MESSAGE_MAP //-V2522 //--------------------------------------------------------------------------------------------------------- // Конец внутреннего класса диалога //--------------------------------------------------------------------------------------------------------- }; //------------------------------------------------------------------------------------------------------------- // Убираем дефайны, чтобы потом не мешали. // От этого они получаются "локального действия", как будто у них была бы область видимости -- функция. На самом // деле это сделано вручную через #undef. Чтобы подчеркнуть их локальную природу, у них имена заканчиваются на _. // Такие дефайны потом не перекосячат весь код после того как, фактически, стали уже не нужны. //------------------------------------------------------------------------------------------------------------- #undef ID_TEXT_ #undef ID_INPUT_ //------------------------------------------------------------------------------------------------------------- // Это статический объект, потому что строка в нем должна жить после завершения функции. //------------------------------------------------------------------------------------------------------------- static inputDlg dlg; //------------------------------------------------------------------------------------------------------------- // Передаем layout и запускаем окно диалога //------------------------------------------------------------------------------------------------------------- dlg.dialogBox (layout); //------------------------------------------------------------------------------------------------------------- // Возвращаем адрес строки из статического объекта. Так можно делать, потому что статический объект не умрет // при выходе из функции и строка в нем, соответственно, тоже. Адрес нестатических переменных передавать // синтаксически можно, но ведет к серьезным ошибкам. //------------------------------------------------------------------------------------------------------------- return dlg.str; } #endif // TX_COMPILED //! @} //} //================================================================================================================= //} //================================================================================================================= //================================================================================================================= //{ TXLIB IMPLEMENTATION // Реализация функций библиотеки //================================================================================================================= //! @cond INTERNAL { //----------------------------------------------------------------------------------------------------------------- //{ The Includes //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< _TX_END_NAMESPACE //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch #pragma warning (disable: 4005) // 'name': macro redefinition #endif #if defined (__STRICT_ANSI__) && defined (__STRICT_ANSI__UNDEFINED) #undef __STRICT_ANSI__ #endif //----------------------------------------------------------------------------------------------------------------- #include <stdarg.h> #include <io.h> #include <fcntl.h> #include <process.h> #include <signal.h> #include <setjmp.h> #include <locale.h> #include <limits.h> #include <stdint.h> #include <map> #include <numeric> #include <exception> #include <stdexcept> #include <tlhelp32.h> #include <shellapi.h> #if defined (_GCC_VER) #include <shlobj.h> #include <cxxabi.h> #include <unwind.h> #endif #if defined (__CYGWIN__) #include <stdarg.h> #include <unistd.h> #include <termios.h> #endif #if defined (_MSC_VER) #include <new.h> #include <shlobj.h> #include <ntstatus.h> #include <crtdbg.h> #include <rtcapi.h> #include <dbghelp.h> #endif #if defined (_GCC_VER) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 #include <inttypes.h> #endif //----------------------------------------------------------------------------------------------------------------- #if defined (TX_USE_SPEAK) //-------------------------------------------------------------------------------------- #include <SAPI.h> // <== ЕСЛИ ЗДЕСЬ ОШИБКА, ТО У ВАС НЕТ ФАЙЛА SAPI.h. No SAPI.h file, TXLib isn't guilty :( #endif //-------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (pop) // MSVC: Restore max level #endif #if defined (__STRICT_ANSI__UNDEFINED) #define __STRICT_ANSI__ // Redefine back #endif //----------------------------------------------------------------------------------------------------------------- _TX_BEGIN_NAMESPACE #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //================================================================================================================= //{ DLL functions import, missing types definitions //! @name Импорт внешних библиотек, определение недостающих типов //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Some of structs, consts and interfaces aren't defined in MinGW some early headers. // Copied from Windows SDK 7.0a. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { #ifndef AC_SRC_ALPHA #define AC_SRC_ALPHA 0x01 #endif #ifndef SMTO_ERRORONEXIT #define SMTO_ERRORONEXIT 0x0020 #endif #ifndef NT_CONSOLE_PROPS_SIG #define NT_CONSOLE_PROPS_SIG 0xA0000002 #endif #ifndef NIIF_INFO #define NIIF_INFO 0x00000001 #define NIIF_WARNING 0x00000002 #define NIIF_ERROR 0x00000003 #endif #ifndef NIF_INFO #define NIF_STATE 0x00000008 #define NIF_INFO 0x00000010 #endif #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004 #endif #ifndef SYMOPT_CASE_INSENSITIVE #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_NO_PROMPTS 0x00080000 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 #define SYMOPT_FAVOR_COMPRESSED 0x00800000 #define SYMOPT_FLAT_DIRECTORY 0x00400000 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 #define SYMOPT_OVERWRITE 0x00100000 #define SYMOPT_DEBUG 0x80000000 #endif // SEH exception codes. For GCC, see http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 64-66. #ifndef STATUS_POSSIBLE_DEADLOCK #define STATUS_POSSIBLE_DEADLOCK 0xC0000194 #endif #ifndef STATUS_FLOAT_MULTIPLE_FAULTS #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4 #endif #ifndef STATUS_STACK_BUFFER_OVERRUN #define STATUS_STACK_BUFFER_OVERRUN 0xC0000409 #endif #ifndef STATUS_ASSERTION_FAILURE #define STATUS_ASSERTION_FAILURE 0xC0000420 #endif #ifndef STATUS_WX86_BREAKPOINT #define STATUS_WX86_BREAKPOINT 0x4000001F #endif #ifndef DBG_PRINTEXCEPTION_C #define DBG_PRINTEXCEPTION_C 0x40010006 // OutputDebugStringA() call #endif #ifndef DBG_PRINTEXCEPTION_WIDE_C #define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A // OutputDebugStringW() call #endif #ifndef DBG_THREAD_NAME #define DBG_THREAD_NAME 0x406D1388 #endif #define EXCEPTION_CPP_MSC 0xE06D7363 // '?msc' #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 0x19930520 // '?msc' version magic, see ehdata.h #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 0x19930521 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 0x19930522 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1 0x01994000 // '?msc' version magic #define EXCEPTION_CPP_GCC 0x20474343 // ' GCC' #define EXCEPTION_CPP_GCC_UNWIND 0x21474343 // '!GCC' #define EXCEPTION_CPP_GCC_FORCED 0x22474343 // '"GCC' #define EXCEPTION_CLR_FAILURE 0xE0434f4D // 'аCOM' #define EXCEPTION_CPP_BORLAND_BUILDER 0x0EEDFAE6 // Should never occur here #define EXCEPTION_CPP_BORLAND_DELPHI 0x0EEDFADE // Should never occur here #pragma pack (push, 1) struct CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; }; struct CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; }; struct CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; }; struct DATABLOCK_HEADER { DWORD cbSize; DWORD dwSignature; }; struct NT_CONSOLE_PROPS { DATABLOCK_HEADER dbh; WORD wFillAttribute; WORD wPopupFillAttribute; COORD dwScreenBufferSize; COORD dwWindowSize; COORD dwWindowOrigin; DWORD nFont; DWORD nInputBufferSize; COORD dwFontSize; UINT uFontFamily; UINT uFontWeight; WCHAR FaceName[LF_FACESIZE]; UINT uCursorSize; BOOL bFullScreen; BOOL bQuickEdit; BOOL bInsertMode; BOOL bAutoPosition; UINT uHistoryBufferSize; UINT uNumberOfHistoryBuffers; BOOL bHistoryNoDup; COLORREF ColorTable[16]; }; struct FLASHWINFO { UINT cbSize; HWND hwnd; DWORD dwFlags; UINT uCount; DWORD dwTimeout; }; enum TBPFLAG { TBPF_NOPROGRESS = 0x0, TBPF_INDETERMINATE = 0x1, TBPF_NORMAL = 0x2, TBPF_ERROR = 0x4, TBPF_PAUSED = 0x8 }; #pragma pack (pop) const GUID IID_IShellLink = {0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_IShellLinkDataList = {0x45e2b4ae, 0xb1c3, 0x11d0, {0xb9,0x2f,0x00,0xa0,0xc9,0x03,0x12,0xe1}}; const GUID IID_IPersistFile = {0x0000010b, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; const GUID CLSID_TaskbarList = {0x56fdf344, 0xfd6d, 0x11d0, {0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}}; const GUID CLSID_SpVoice = {0x96749377, 0x3391, 0x11d2, {0x9e,0xe3,0x00,0xc0,0x4f,0x79,0x73,0x96}}; const GUID IID_ISpVoice = {0x6c44df74, 0x72b9, 0x4992, {0xa1,0xec,0xef,0x99,0x6e,0x04,0x22,0xd4}}; typedef DWORD NTSTATUS; typedef ULONG_PTR KAFFINITY; typedef LONG KPRIORITY; struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; wchar_t* Buffer; }; struct RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; UNICODE_STRING DosPath; }; struct CURDIR { UNICODE_STRING DosPath; void* Handle; }; struct RTL_USER_PROCESS_PARAMETERS { ULONG AllocationSize; ULONG Size; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; CURDIR CurrentDirectory; UNICODE_STRING DllPath; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; wchar_t* Environment; ULONG dwX; ULONG dwY; ULONG dwXSize; ULONG dwYSize; ULONG dwXCountChars; ULONG dwYCountChars; ULONG dwFillAttribute; ULONG dwFlags; ULONG wShowWindow; UNICODE_STRING WindowTitle; UNICODE_STRING Desktop; UNICODE_STRING ShellInfo; UNICODE_STRING RuntimeInfo; RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; }; struct PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; void* Reserved3[2]; void* Ldr; RTL_USER_PROCESS_PARAMETERS* ProcessParameters; void* Reserved4[3]; void* AtlThunkSListPtr; void* Reserved5; ULONG Reserved6; void* Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; void* Reserved9[45]; BYTE Reserved10[96]; void* PostProcessInitRoutine; BYTE Reserved11[128]; void* Reserved12[1]; ULONG SessionId; }; struct TEB { void* Reserved1[12]; PEB* ProcessEnvironmentBlock; void* Reserved2[399]; BYTE Reserved3[1952]; void* TlsSlots[64]; BYTE Reserved4[8]; void* Reserved5[26]; void* ReservedForOle; void* Reserved6[4]; void* TlsExpansionSlots; }; struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PEB* PebBaseAddress; KAFFINITY AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; }; enum ADDRESS_MODE { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat }; struct ADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; }; struct KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64 Reserved[5]; }; struct STACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; void* FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; }; struct WOW64_FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE RegisterArea[80]; DWORD Cr0NpxState; }; #pragma pack (push, 4) struct WOW64_CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; WOW64_FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[512]; }; #pragma pack (pop) struct SYMBOL_INFO { ULONG SizeOfStruct; ULONG TypeIndex; ULONG64 Reserved[2]; ULONG info; ULONG Size; ULONG64 ModBase; ULONG Flags; ULONG64 Value; ULONG64 Address; ULONG Register; ULONG Scope; ULONG Tag; ULONG NameLen; ULONG MaxNameLen; char Name[1]; }; struct IMAGEHLP_LINE64 { DWORD SizeOfStruct; void* Key; DWORD LineNumber; char* FileName; DWORD64 Address; }; typedef bool (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64) (HANDLE process, DWORD64 baseAddress, void* buffer, DWORD size, DWORD* bytesRead); typedef void* (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64) (HANDLE process, DWORD64 baseAddress); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64) (HANDLE process, DWORD64 address); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64) (HANDLE process, HANDLE thread, ADDRESS64* address); typedef void (*unexpected_handler)(); #pragma pack (push, 4) struct MINIDUMP_THREAD_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; }; struct MINIDUMP_THREAD_EX_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; ULONG64 BackingStoreBase; ULONG64 BackingStoreEnd; }; struct MINIDUMP_MODULE_CALLBACK { wchar_t* FullPath; ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; VS_FIXEDFILEINFO VersionInfo; void* CvRecord; ULONG SizeOfCvRecord; void* MiscRecord; ULONG SizeOfMiscRecord; }; struct MINIDUMP_INCLUDE_THREAD_CALLBACK { ULONG ThreadId; }; struct MINIDUMP_INCLUDE_MODULE_CALLBACK { ULONG64 BaseOfImage; }; struct MINIDUMP_MEMORY_INFO { ULONG64 BaseAddress; ULONG64 AllocationBase; ULONG32 AllocationProtect; ULONG32 __alignment1; ULONG64 RegionSize; ULONG32 State; ULONG32 Protect; ULONG32 Type; ULONG32 __alignment2; }; struct MINIDUMP_USER_STREAM { ULONG32 Type; ULONG BufferSize; void* Buffer; }; struct MINIDUMP_USER_STREAM_INFORMATION { ULONG UserStreamCount; MINIDUMP_USER_STREAM* UserStreamArray; }; struct MINIDUMP_CALLBACK_INPUT { ULONG ProcessId; HANDLE ProcessHandle; ULONG CallbackType; union //-V2514 { MINIDUMP_THREAD_CALLBACK Thread; MINIDUMP_THREAD_EX_CALLBACK ThreadEx; MINIDUMP_MODULE_CALLBACK Module; MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; }; }; struct MINIDUMP_CALLBACK_OUTPUT { union //-V2514 { ULONG ModuleWriteFlags; ULONG ThreadWriteFlags; ULONG SecondaryFlags; struct { ULONG64 MemoryBase; ULONG MemorySize; }; struct { unsigned CheckCancel; unsigned Cancel; }; HANDLE Handle; //-V117 }; struct { MINIDUMP_MEMORY_INFO VmRegion; unsigned Continue; }; HRESULT Status; }; struct MINIDUMP_EXCEPTION_INFORMATION { DWORD ThreadId; EXCEPTION_POINTERS* ExceptionPointers; unsigned ClientPointers; }; typedef int (WINAPI* MINIDUMP_CALLBACK_ROUTINE) (void* param, MINIDUMP_CALLBACK_INPUT* input, MINIDUMP_CALLBACK_OUTPUT* output); struct MINIDUMP_CALLBACK_INFORMATION { MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; void* CallbackParam; }; enum MINIDUMP_TYPE { MiniDumpNormal = 0x00000000, MiniDumpWithDataSegs = 0x00000001, MiniDumpWithFullMemory = 0x00000002, MiniDumpWithHandleData = 0x00000004, MiniDumpFilterMemory = 0x00000008, MiniDumpScanMemory = 0x00000010, MiniDumpWithUnloadedModules = 0x00000020, MiniDumpWithIndirectlyReferencedMemory = 0x00000040, MiniDumpFilterModulePaths = 0x00000080, MiniDumpWithProcessThreadData = 0x00000100, MiniDumpWithPrivateReadWriteMemory = 0x00000200, MiniDumpWithoutOptionalData = 0x00000400, MiniDumpWithFullMemoryInfo = 0x00000800, MiniDumpWithThreadInfo = 0x00001000, MiniDumpWithCodeSegs = 0x00002000, MiniDumpWithoutAuxiliaryState = 0x00004000, MiniDumpWithFullAuxiliaryState = 0x00008000, MiniDumpWithPrivateWriteCopyMemory = 0x00010000, MiniDumpIgnoreInaccessibleMemory = 0x00020000, MiniDumpWithTokenInformation = 0x00040000 }; #ifndef CONTEXT_ALL #define CONTEXT_ALL ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS ) #endif #pragma pack (pop) } // namespace Win32 #endif // TX_COMPILED #define FOREGROUND_BLACK ( 0 ) #define FOREGROUND_CYAN ( FOREGROUND_BLUE | FOREGROUND_GREEN ) #define FOREGROUND_MAGENTA ( FOREGROUND_BLUE | FOREGROUND_RED ) #define FOREGROUND_DARKYELLOW ( FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_LIGHTGRAY ( FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_DARKGRAY ( FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTBLUE ( FOREGROUND_BLUE | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTGREEN ( FOREGROUND_GREEN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTCYAN ( FOREGROUND_CYAN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTRED ( FOREGROUND_RED | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTMAGENTA ( FOREGROUND_MAGENTA | FOREGROUND_INTENSITY ) #define FOREGROUND_YELLOW ( FOREGROUND_DARKYELLOW | FOREGROUND_INTENSITY ) #define FOREGROUND_WHITE ( FOREGROUND_LIGHTGRAY | FOREGROUND_INTENSITY ) #define BACKGROUND_BLACK ( 0 ) #define BACKGROUND_CYAN ( BACKGROUND_BLUE | BACKGROUND_GREEN ) #define BACKGROUND_MAGENTA ( BACKGROUND_BLUE | BACKGROUND_RED ) #define BACKGROUND_DARKYELLOW ( BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_GRAY ( BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_DARKGRAY ( BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTBLUE ( BACKGROUND_BLUE | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTGREEN ( BACKGROUND_GREEN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTCYAN ( BACKGROUND_CYAN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTRED ( BACKGROUND_RED | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTMAGENTA ( BACKGROUND_MAGENTA | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTYELLOW ( BACKGROUND_DARKYELLOW | BACKGROUND_INTENSITY ) #define BACKGROUND_WHITE ( BACKGROUND_DARKGRAY | BACKGROUND_INTENSITY ) //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ There are copies of MSVC compiler built-in predefined definitions, which are wrong in 64-bit mode. // So we have to override them. See: http://stackoverflow.com/questions/39113168 //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< #if defined (_MSC_VER) // MS ABI C++ Exception Layout namespace Win32 { // --------------------------- // #pragma pack (push, 4) // EXCEPTION_RECORD: // +==================================================+ struct ThrowInfo // |... | { // |NumberParameters: 3, 4 or more | __int32 attributes; // |ExceptionInformation[0]: MS signature 0x19930520 | __int32 pmfnUnwind; // |ExceptionInformation[1]: object* thrown | __int32 pForwardCompat; // |ExceptionInformation[2]: ThrowInfo* --------------+---+ __int32 pCatchableTypeArray; // |ExceptionInformation[3]: ImageBase (if params > 3)| | }; // +==================================================+ | // | struct CatchableTypeArray // ThrowInfo: | { // +======================================+ <-------+ __int32 nCatchableTypes; // | ... | __int32 arrayOfCatchableTypes[]; // +-----+-- pCatchableTypeArray (ptr/RVA) | }; // | +======================================+ // | struct CatchableType // | CatchableTypeArray: { // +---> +======================================+ __int32 properties; // | ... | __int32 pType; // +-----+-- arrayOfCatchableTypes[0] (ptr/RVA) | __int32 thisDisplacement[3]; // struct _PMD // | +======================================+ __int32 sizeOrOffset; // | __int32 copyFunction; // | CatchableType: }; // +---> +====================+ // | ... | std::type_info: #pragma pack (pop) // | pType (ptr/RVA) ---+------> +==================+ // | ... | |type_info data | } // namespace Win32 // +====================+ |... | // +==================+ #endif // Similar to __CxxDetectRethrow(), see C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\crtsrc\vcruntime\frame.cpp: #define _TX_MSC__CXX_DETECT_RETHROW( exc ) \ ( \ (exc) && \ (exc) -> ExceptionCode == EXCEPTION_CPP_MSC && \ (exc) -> NumberParameters >= 3 && \ \ ((exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3) && \ \ (exc) -> ExceptionInformation[2] == 0 \ ) #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ The corresponding structures for GCC // // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h // See: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi //----------------------------------------------------------------------------------------------------------------- #if defined (_GCC_VER) #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // GCC ABI C++ Exception layout. A/B are ExceptionInformation[0]. namespace ABI { // -------------------------------------------------------------- // struct __cxa_exception // Case A: "_Unwind_Exception* A" is undependent exception: { // -------------------------------------------------------- union { // struct // __cxa_exception: std::type_info: { // -*--+====================+ +==================+ ::std::type_info* exceptionType; // ^ |exceptionType* -----+---->|type_info data | void (*exceptionDestructor)(void*); // | |... | |... | }; // -1 | | +==================+ struct // | | | { // A >----|--+--------------------+ __cxa_exception* primaryException; // | | |unwindHeader | void (*padding)(); // +1 | | | }; // | | | | }; // V | | | // -*--- +====================+ void (*unexpected_handler)(); // |object | std::terminate_handler terminateHandler; // +--------------------+ // __cxa_exception* nextException; // Case B: "_Unwind_Exception* B" is dependent exception int handlerCount; // (unwindHeader.exception_class & 1 != 0): int handlerSwitchValue; // ----------------------------------------------------- const unsigned char* actionRecord; // const unsigned char* languageSpecificData; // __cxa_exception: __cxa_exception: void* catchTemp; // -*--+====================+ -*--+=================+ void* adjustedPtr; // ^ |primaryException* --+-- ^ |exceptionType* | // | |... | \ | |... | _Unwind_Exception unwindHeader; // -1 | | | | | | }; // | | | | | | | // B >----|--+--------------------+ | -1 +-----------------+ struct __cxa_eh_globals // | | |unwindHeader | | | |unwindHeader | { // +1 | | | | | | | __cxa_exception* caughtExceptions; // | | | | | | | | unsigned int uncaughtExceptions; // V | | | \ | | | }; // -*--- +====================+ -->*--+=================+ // |... | |object | } // namespace ABI // . . | | // +-----------------+ extern "C" ABI::__cxa_eh_globals* __cxa_get_globals(); #endif // TX_COMPILED #endif //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Hand-made IAT. // Some IDEs don't link with these libs by default in console projects, so do sunrise by hand. :( //----------------------------------------------------------------------------------------------------------------- // Hand-made DLLIMPORT helpers #define _TX_DLLIMPORT( lib, retval, name, params ) TX_DLLIMPORT (true, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_OPT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_CRT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, please) void (*_txDllImport (const char dllFileName[], const char funcName[], bool required = true)) (); //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { _TX_DLLIMPORT ("GDI32", HDC, CreateCompatibleDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateCompatibleBitmap, (HDC dc, int width, int height)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetStockObject, (int object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, SelectObject, (HDC dc, HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetCurrentObject, (HDC dc, unsigned objectType)); _TX_DLLIMPORT ("GDI32", int, GetObjectA, (HGDIOBJ obj, int bufsize, void* buffer)); _TX_DLLIMPORT ("GDI32", DWORD, GetObjectType, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", bool, DeleteDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", bool, DeleteObject, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", COLORREF, SetTextColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, SetBkColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", int, SetBkMode, (HDC dc, int bkMode)); _TX_DLLIMPORT ("GDI32", HFONT, CreateFontA, (int height, int width, int escapement, int orientation, int weight, DWORD italic, DWORD underline, DWORD strikeout, DWORD charSet, DWORD outputPrec, DWORD clipPrec, DWORD quality, DWORD pitchAndFamily, const char face[])); _TX_DLLIMPORT ("GDI32", int, EnumFontFamiliesExA, (HDC dc, LPLOGFONT logFont, FONTENUMPROC enumProc, LPARAM lParam, DWORD reserved)); _TX_DLLIMPORT ("GDI32", COLORREF, SetPixel, (HDC dc, int x, int y, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, GetPixel, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", HPEN, CreatePen, (int penStyle, int width, COLORREF color)); _TX_DLLIMPORT ("GDI32", HBRUSH, CreateSolidBrush, (COLORREF color)); _TX_DLLIMPORT ("GDI32", bool, MoveToEx, (HDC dc, int x, int y, POINT* point)); _TX_DLLIMPORT ("GDI32", bool, LineTo, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", bool, Polygon, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Polyline, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, PolyBezier, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Rectangle, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, RoundRect, (HDC dc, int x0, int y0, int x1, int y1, int sizeX, int sizeY)); _TX_DLLIMPORT ("GDI32", bool, Ellipse, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, Arc, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Pie, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Chord, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, TextOutA, (HDC dc, int x, int y, const char string[], int length)); _TX_DLLIMPORT ("GDI32", UINT, SetTextAlign, (HDC dc, unsigned mode)); _TX_DLLIMPORT ("GDI32", bool, GetTextExtentPoint32A, (HDC dc, const char string[], int length, SIZE* size)); _TX_DLLIMPORT ("GDI32", bool, ExtFloodFill, (HDC dc, int x, int y, COLORREF color, unsigned type)); _TX_DLLIMPORT ("GDI32", bool, BitBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, StretchBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, PlgBlt, (HDC dest, const POINT* parallelogram, HDC src, int xSrc, int ySrc, int width, int height, HBITMAP mask, int xMask, int yMask)); _TX_DLLIMPORT ("GDI32", int, SetDIBitsToDevice, (HDC dc, int xDest, int yDest, DWORD width, DWORD height, int xSrc, int ySrc, unsigned startLine, unsigned numLines, const void* data, const BITMAPINFO* info, unsigned colorUse)); _TX_DLLIMPORT ("GDI32", int, GetDIBits, (HDC hdc, HBITMAP hbmp, unsigned uStartScan, unsigned cScanLines, void* lpvBits, BITMAPINFO* lpbi, unsigned usage)); _TX_DLLIMPORT ("GDI32", bool, PatBlt, (HDC dc, int x0, int y0, int width, int height, DWORD rOp)); _TX_DLLIMPORT ("GDI32", int, SetROP2, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", int, SetStretchBltMode, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", DWORD, GdiSetBatchLimit, (DWORD limit)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateDIBSection, (HDC dc, const BITMAPINFO* bmInfo, unsigned colorUsage, void **vBits, HANDLE section, DWORD offset)); _TX_DLLIMPORT ("User32", int, DrawTextA, (HDC dc, const char text[], int length, RECT* rect, unsigned format)); _TX_DLLIMPORT ("User32", HANDLE, LoadImageA, (HINSTANCE inst, const char name[], unsigned type, int sizex, int sizey, unsigned mode)); _TX_DLLIMPORT_OPT ("User32", bool, IsHungAppWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", HWND, GhostWindowFromHungWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", bool, FlashWindowEx, (const FLASHWINFO* flash)); _TX_DLLIMPORT ("WinMM", bool, PlaySound, (const char sound[], HMODULE mod, DWORD mode)); _TX_DLLIMPORT_OPT ("MSImg32", bool, TransparentBlt, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, unsigned transparentColor)); _TX_DLLIMPORT_OPT ("MSImg32", bool, AlphaBlend, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, BLENDFUNCTION blending)); _TX_DLLIMPORT ("Kernel32", void, ExitProcess, (unsigned retcode)); _TX_DLLIMPORT ("Kernel32", bool, TerminateProcess, (HANDLE process, unsigned retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalExit, (int retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalAppExitA, (unsigned action, const char message[])); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetThreadId, (HANDLE thread)); _TX_DLLIMPORT ("Kernel32", HWND, GetConsoleWindow, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetConsoleFont, (HANDLE con, DWORD fontIndex)); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetNumberOfConsoleFonts, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFont, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFO* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", void, RtlCaptureContext, (CONTEXT* contextRecord)); _TX_DLLIMPORT_OPT ("Kernel32", USHORT, RtlCaptureStackBackTrace, (DWORD framesToSkip, DWORD framesToCapture, void** backTrace, DWORD* hash)); _TX_DLLIMPORT_OPT ("Kernel32", void*, AddVectoredExceptionHandler, (unsigned long firstHandler, PVECTORED_EXCEPTION_HANDLER handler)); _TX_DLLIMPORT_OPT ("Kernel32", unsigned, RemoveVectoredExceptionHandler,(void* handler)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetModuleHandleEx, (DWORD flags, const char moduleName[], HMODULE* module)); _TX_DLLIMPORT_OPT ("Kernel32", bool, IsWow64Process, (HANDLE process, int* isWow64Process)); _TX_DLLIMPORT_OPT ("Kernel32", bool, Wow64GetThreadContext, (HANDLE thread, WOW64_CONTEXT* context)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetThreadStackGuarantee, (unsigned long* stackSize)); _TX_DLLIMPORT ("OLE32", HRESULT, CoInitialize, (void*)); _TX_DLLIMPORT ("OLE32", HRESULT, CoCreateInstance, (REFCLSID clsId, IUnknown*, DWORD, REFIID iId, void** value)); _TX_DLLIMPORT ("OLE32", void, CoUninitialize, (void)); _TX_DLLIMPORT ("Shell32", HINSTANCE,ShellExecuteA, (HWND wnd, const char operation[], const char file[], const char parameters[], const char directory[], int showCmd)); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIA, (const char string[], const char search[])); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIW, (const wchar_t string[], const wchar_t search[])); _TX_DLLIMPORT_OPT ("NTDLL", char*, wine_get_version, (void)); _TX_DLLIMPORT ("NTDLL", NTSTATUS, NtQueryInformationProcess, (HANDLE process, int infoClass, void* processInfo, unsigned long szProcessInfo, unsigned long* szReturnInfo)); _TX_DLLIMPORT_CRT ("MSVCRT", void, exit, (int retcode)); _TX_DLLIMPORT_CRT ("MSVCRT", void, _cexit, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _fpreset, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _controlfp, (unsigned control, unsigned mask)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthread, (void (__cdecl* start_address) (void*), unsigned stack_size, void* arglist)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthreadex, (void* security, unsigned stack_size, unsigned (__stdcall* start_address) (void*), void *arglist, unsigned init_flag, unsigned* thread_addr)); _TX_DLLIMPORT_CRT ("MSVCRT", char*, __unDName, (char* outStr, const char* mangledName, int outStrLen, void* (*mallocFunc) (size_t size), void (*freeFunc) (void *pointer), unsigned short flags)); _TX_DLLIMPORT_CRT ("MSVCRT", unexpected_handler, set_unexpected, (unexpected_handler handler)); _TX_DLLIMPORT_OPT ("OpenGL32", HDC, wglGetCurrentDC, (void)); _TX_DLLIMPORT_OPT ("OpenGL32", unsigned, glGetError, (void)); _TX_DLLIMPORT_OPT ("Glu32", const char*, gluErrorString, (unsigned error)); _TX_DLLIMPORT_OPT ("ComDlg32", DWORD, CommDlgExtendedError, (void)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, MiniDumpWriteDump, (HANDLE process, DWORD processId, HANDLE file, MINIDUMP_TYPE dumpType, MINIDUMP_EXCEPTION_INFORMATION* exceptionParam, MINIDUMP_USER_STREAM_INFORMATION* userStreamParam, MINIDUMP_CALLBACK_INFORMATION* callbackParam)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("DbgHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); namespace MinGW { _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("MgwHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); } // namespace MinGW } // namespace Win32 #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal function prototypes, macros and constants // @name Прототипы внутренних функций, макросы и константы //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize(); void _txCleanup(); HWND _txCanvas_CreateWindow (const SIZE* size); bool _txCanvas_OnCREATE (HWND wnd); bool _txCanvas_OnDESTROY (HWND wnd); bool _txCanvas_OnCLOSE (HWND); bool _txCanvas_OnPAINT (HWND wnd); bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down); bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info); bool _txCanvas_OnTIMER (HWND wnd, WPARAM id); bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords); bool _txCanvas_OnMOUSELEAVE (HWND wnd); bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd); bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd); unsigned WINAPI _txCanvas_ThreadProc (void* data); LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard; bool _txBuffer_Delete (HDC* dc); bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC()); HWND _txConsole_Attach(); bool _txConsole_OK() tx_nodiscard; bool _txConsole_Detach (bool activate); bool _txConsole_Draw (HDC dc); bool _txConsole_SetUnicodeFont(); const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra); HWND txCreateExtraWindow (CREATESTRUCT createData); HICON _txCreateTXIcon (int size) tx_nodiscard; int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL, int checkOfs = 0, const wchar_t checkLetters[2] = NULL); int _txPauseBeforeTermination (HWND canvas); int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard; void _txActivateWindow (HWND wnd, unsigned mode); int _txGetInput(); LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); const char* _txPlayVideo_FindVLC() tx_nodiscard; bool _txCreateShortcut (const char shortcutName[], const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL, const char description[] = NULL, int cmdShow = SW_SHOWNORMAL, const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0, COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD)); void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) tx_nodiscard; void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]); const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args); void _txOnTerminate(); void _txOnUnexpected(); void _txOnPureCall(); void _txOnNewHandlerAnsi(); int _txOnNewHandler (size_t size); void _txOnSignal (int signal = 0, int fpe = 0); BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type); void _txOnSecurityError (int code, void*); void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code); int _txOnMatherr (_exception* except); void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned line, uintptr_t); int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line); int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5); int _txOnErrorReport (int type, const char* text, int* ret); int tx_glGetError (int setError = INT_MIN); void _txOnCExit(); void _txOnExit (int retcode); void _txOnFatalExit (int retcode); void _txOnExitProcess (unsigned retcode); void _txOnFatalAppExitA (unsigned action, const char message[]); bool _txOnTerminateProcess (HANDLE process, unsigned retcode); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter); void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc); long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc); long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]); intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]); intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type); intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0, unsigned params = 0, const ULONG_PTR info[] = NULL); void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?", bool readSource = true); const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true, CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread()); int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL, HANDLE thread = GetCurrentThread()); const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false); const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2); bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL, Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL, const char** source = NULL, int context = 2); intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN); bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL); uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL, int useHotPatching = false, HMODULE module = NULL, bool debug = false); bool _txInDll() tx_nodiscard; PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard; bool _txKillProcess (DWORD pid); int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/); bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true); bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid()); IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard; bool _txIsConsoleSubsystem(); const char* _txAppInfo() tx_nodiscard; #if defined (_CLANG_VER) && !defined (_MSC_VER) void _txLibCppDebugFunction (std::__libcpp_debug_info const& info); #endif #endif // TX_COMPILED inline bool _txCanvas_OK () tx_nodiscard; int _txCanvas_SetRefreshLock (int count); const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0, const char msg[] = NULL, ...) tx_printfy (5); bool _txIsBadReadPtr (const void* address); intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3); intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg); bool _txIsTTY (int fd); void txReopenStdio(); #if defined (__CYGWIN__) int _getch(); int _putch (int ch); int _kbhit() tx_nodiscard; #endif //----------------------------------------------------------------------------------------------------------------- // There are macros for __FILE__ and __LINE__ to work properly. #if !defined (NDEBUG) #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \ (assert (cond), true) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Параметр \"%s\" неверен." \ " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка.", #dc), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (TX_ERROR ("\a" "%s" \ "Если вы указали параметр \"%s\", то он неверен.%s", \ (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \ #dc, \ ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка." : "")), 1) ) #else #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #endif //----------------------------------------------------------------------------------------------------------------- // Take action in debug configuration only. // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'( #if !defined (NDEBUG) #define _TX_ON_DEBUG( code ) { code; } #else #define _TX_ON_DEBUG( code ) ; #endif //----------------------------------------------------------------------------------------------------------------- // Invokes an error without location information. "$$" restores TX-related call location context #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__) //----------------------------------------------------------------------------------------------------------------- // Safe call of a function via its pointer #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 ) #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 ) //----------------------------------------------------------------------------------------------------------------- // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x. #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \ !(cond) && GetTickCount() < _t; \ Sleep (_txWindowUpdateInterval)) \ ; \ \ if (!(cond)) \ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); } //----------------------------------------------------------------------------------------------------------------- // Detouring in case of SEH mechanism #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 ) #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; } //----------------------------------------------------------------------------------------------------------------- // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code. #if defined (IN) // #undef IN #endif #if defined (OUT) // #undef OUT #endif //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal global data //! @name Внутренние глобальные данные // // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :) // // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же. // Здесь это сделано только в образовательных целях. // // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс. //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<< const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна _TX_IDM_CONSOLE = 40001, _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas //----------------------------------------------------------------------------------------------------------------- volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize(); volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main() volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT() RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0] HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP), // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock() UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question. int _txConsole = false; // Only first TXLib module in app can own the console bool _txMain = false; // First TXLib wnd opened (closing it terminates program) bool _txIsDll = false; // TXLib module is in DLL volatile bool _txRunning = false; // main() is still running volatile bool _txExit = false; // exit() is active volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE() volatile unsigned _txMouseButtons = 0; volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook(). _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro volatile int _txErrors = 0; // TX_ERROR calls sequental number volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError() volatile long _txSENumber = 0; // SEH exceptions sequental number volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess, (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA, (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp, (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier, (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler, (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace, (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize, (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions, (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64, (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr, (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup, (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64, (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64, (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64, (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext }; volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- extern volatile unsigned _txCanaryFirst; extern volatile unsigned _txCanaryLast; extern volatile HWND _txCanvas_Window; extern volatile unsigned _txCanvas_ThreadId; extern HDC _txCanvas_BackBuf[2]; extern RGBQUAD* _txCanvas_Pixels; extern volatile int _txCanvas_RefreshLock; extern volatile WNDPROC _txAltWndProc; extern volatile bool _txExit; extern volatile int _txOGLError; //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib engine init/check/cleanup //! @name Инициализация/проверка/завершение TXLib //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Early initialization //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize() { if (_txInitialized) return 1; _txInitialized = 1; #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585 #endif #if defined (_TX_ALLOW_TRACE) _txLocLvlSet (1); #endif _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" " "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n"); OutputDebugString ("\n")); _txMainThreadId = GetCurrentThreadId(); _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId); $3 _txIsDll = _txInDll(); $ if (!_txIsDll) { $ _txConsole = ! FindAtom ("_txConsole"); $ (void) AddAtom ("_txConsole"); //-V530 } $ if (_txConsole) { $ _txCheckSourceCP (_TX_CODEPAGE, true); $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ _txOnSignal(); $ if (!*_txLogName) {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); } $ if (!_txIsDll) { $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler)); $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter); } $ ::std::set_terminate (_txOnTerminate); $ ::std::set_new_handler (_txOnNewHandlerAnsi); $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected)); #if defined (_CLANG_VER) && !defined (_MSC_VER) $ ::std::__libcpp_debug_function = _txLibCppDebugFunction; #endif $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true); $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #if defined (_MSC_VER) $ _set_printf_count_output (1); $ _set_new_handler (_txOnNewHandler); $ _set_new_mode (1); #if !defined (_CLANG_VER) $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); $ _CrtSetAllocHook (_txOnAllocHook); $ unsigned mode = _CRTDBG_MODE_FILE; $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0; $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode); $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG); $ _set_abort_behavior (0, _CALL_REPORTFAULT); $ _RTC_SetErrorFunc (_txOnRTCFailure); $ _set_purecall_handler (_txOnPureCall); $ _set_invalid_parameter_handler (_txOnInvalidParam); #endif #if defined (__STDC_LIB_EXT1__) $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi); #endif #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386) $ __setusermatherr (_txOnMatherr); #endif #if !defined (__CYGWIN__) $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR); #endif $ HWND console = _txConsole_Attach(); $ SetWindowTextA (console, txGetModuleFileName (false)); } $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL"); $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL"); $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit); $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit); $ InitializeCriticalSection (&_txCanvas_LockBackBuf); $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted; $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted; $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted; $ Win32::DeleteDC (dc) asserted; $ atexit (_txCleanup); $ if (_txConsole) { $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ tx_fpreset(); $ srand ((unsigned) time (NULL)); //-V202 $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif } $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used" $ return 1; } //----------------------------------------------------------------------------------------------------------------- bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/) { $3 const char* sCodePage = NULL; $ int codePage = 0; $ switch (((unsigned const char*) "А") [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
6879  // диалога | элемента | фикатор |-----------------| (см. описание элементов // | | элемента | X | Y |Шир.|Выс.| окон диалога в MSDN) //----------------------+----------+-----------+---+---+----+----+--------------------------------------------- // | | | | | | | {{ txDialog::DIALOG, caption, 0, 0, 0, 240, 85 }, { txDialog::STATIC, text, ID_TEXT_, 10, 10, 150, 40, SS_LEFT }, { txDialog::EDIT, input, ID_INPUT_, 10, 60, 220, 15, ES_LEFT | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP }, { txDialog::BUTTON, "&OK", IDOK, 180, 10, 50, 15, BS_DEFPUSHBUTTON | WS_TABSTOP }, { txDialog::BUTTON, "&Cancel", IDCANCEL, 180, 30, 50, 15, BS_PUSHBUTTON | WS_TABSTOP }, { txDialog::END }}; //------------------------------------------------------------------------------------------------------------- // Класс диалога для InputBox. Внутренний, т.к. зачем ему быть внешним. // Нужен в основном для задания строки ввода (str) и оконной функции диалогового окна, требуемой Win32 (она // построена макросами TX_BEGIN_MESSAGE_MAP и другими). Можно не делать внутреннего класса, но тогда оконную // функцию придется писать в глобальной области видимости, и str объявлять глобально тоже (или передавать ее // адрес через DialogBoxParam и записывать его в класс во время обработки WM_INITDIALOG). //------------------------------------------------------------------------------------------------------------- struct inputDlg : txDialog { char str [1024]; //--------------------------------------------------------------------------------------------------------- inputDlg() : str() {} //--------------------------------------------------------------------------------------------------------- TX_BEGIN_MESSAGE_MAP() // Карта сообщений (на самом деле это начало оконной функции). //-V2525 TX_COMMAND_MAP // Здесь обрабатываются WM_COMMAND (на самом деле это оператор switch). //------------------------------------------------------------------------------------------------- // При нажатии кнопки OK копируем строку из поля ввода в нашу переменную str, т.к. после закрытия // диалога строка ввода умрет и текст уже из нее получить. // Этот макрос на самом деле превращается в case из оператора switch. // _wnd -- это параметр оконной функции, см. определение макроса TX_BEGIN_MESSAGE_MAP(). //------------------------------------------------------------------------------------------------- TX_HANDLE (IDOK) GetDlgItemText (_wnd, ID_INPUT_, str, sizeof (str) - 1); TX_END_MESSAGE_MAP //-V2522 //--------------------------------------------------------------------------------------------------------- // Конец внутреннего класса диалога //--------------------------------------------------------------------------------------------------------- }; //------------------------------------------------------------------------------------------------------------- // Убираем дефайны, чтобы потом не мешали. // От этого они получаются "локального действия", как будто у них была бы область видимости -- функция. На самом // деле это сделано вручную через #undef. Чтобы подчеркнуть их локальную природу, у них имена заканчиваются на _. // Такие дефайны потом не перекосячат весь код после того как, фактически, стали уже не нужны. //------------------------------------------------------------------------------------------------------------- #undef ID_TEXT_ #undef ID_INPUT_ //------------------------------------------------------------------------------------------------------------- // Это статический объект, потому что строка в нем должна жить после завершения функции. //------------------------------------------------------------------------------------------------------------- static inputDlg dlg; //------------------------------------------------------------------------------------------------------------- // Передаем layout и запускаем окно диалога //------------------------------------------------------------------------------------------------------------- dlg.dialogBox (layout); //------------------------------------------------------------------------------------------------------------- // Возвращаем адрес строки из статического объекта. Так можно делать, потому что статический объект не умрет // при выходе из функции и строка в нем, соответственно, тоже. Адрес нестатических переменных передавать // синтаксически можно, но ведет к серьезным ошибкам. //------------------------------------------------------------------------------------------------------------- return dlg.str; } #endif // TX_COMPILED //! @} //} //================================================================================================================= //} //================================================================================================================= //================================================================================================================= //{ TXLIB IMPLEMENTATION // Реализация функций библиотеки //================================================================================================================= //! @cond INTERNAL { //----------------------------------------------------------------------------------------------------------------- //{ The Includes //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< _TX_END_NAMESPACE //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch #pragma warning (disable: 4005) // 'name': macro redefinition #endif #if defined (__STRICT_ANSI__) && defined (__STRICT_ANSI__UNDEFINED) #undef __STRICT_ANSI__ #endif //----------------------------------------------------------------------------------------------------------------- #include <stdarg.h> #include <io.h> #include <fcntl.h> #include <process.h> #include <signal.h> #include <setjmp.h> #include <locale.h> #include <limits.h> #include <stdint.h> #include <map> #include <numeric> #include <exception> #include <stdexcept> #include <tlhelp32.h> #include <shellapi.h> #if defined (_GCC_VER) #include <shlobj.h> #include <cxxabi.h> #include <unwind.h> #endif #if defined (__CYGWIN__) #include <stdarg.h> #include <unistd.h> #include <termios.h> #endif #if defined (_MSC_VER) #include <new.h> #include <shlobj.h> #include <ntstatus.h> #include <crtdbg.h> #include <rtcapi.h> #include <dbghelp.h> #endif #if defined (_GCC_VER) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 #include <inttypes.h> #endif //----------------------------------------------------------------------------------------------------------------- #if defined (TX_USE_SPEAK) //-------------------------------------------------------------------------------------- #include <SAPI.h> // <== ЕСЛИ ЗДЕСЬ ОШИБКА, ТО У ВАС НЕТ ФАЙЛА SAPI.h. No SAPI.h file, TXLib isn't guilty :( #endif //-------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (pop) // MSVC: Restore max level #endif #if defined (__STRICT_ANSI__UNDEFINED) #define __STRICT_ANSI__ // Redefine back #endif //----------------------------------------------------------------------------------------------------------------- _TX_BEGIN_NAMESPACE #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //================================================================================================================= //{ DLL functions import, missing types definitions //! @name Импорт внешних библиотек, определение недостающих типов //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Some of structs, consts and interfaces aren't defined in MinGW some early headers. // Copied from Windows SDK 7.0a. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { #ifndef AC_SRC_ALPHA #define AC_SRC_ALPHA 0x01 #endif #ifndef SMTO_ERRORONEXIT #define SMTO_ERRORONEXIT 0x0020 #endif #ifndef NT_CONSOLE_PROPS_SIG #define NT_CONSOLE_PROPS_SIG 0xA0000002 #endif #ifndef NIIF_INFO #define NIIF_INFO 0x00000001 #define NIIF_WARNING 0x00000002 #define NIIF_ERROR 0x00000003 #endif #ifndef NIF_INFO #define NIF_STATE 0x00000008 #define NIF_INFO 0x00000010 #endif #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004 #endif #ifndef SYMOPT_CASE_INSENSITIVE #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_NO_PROMPTS 0x00080000 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 #define SYMOPT_FAVOR_COMPRESSED 0x00800000 #define SYMOPT_FLAT_DIRECTORY 0x00400000 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 #define SYMOPT_OVERWRITE 0x00100000 #define SYMOPT_DEBUG 0x80000000 #endif // SEH exception codes. For GCC, see http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 64-66. #ifndef STATUS_POSSIBLE_DEADLOCK #define STATUS_POSSIBLE_DEADLOCK 0xC0000194 #endif #ifndef STATUS_FLOAT_MULTIPLE_FAULTS #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4 #endif #ifndef STATUS_STACK_BUFFER_OVERRUN #define STATUS_STACK_BUFFER_OVERRUN 0xC0000409 #endif #ifndef STATUS_ASSERTION_FAILURE #define STATUS_ASSERTION_FAILURE 0xC0000420 #endif #ifndef STATUS_WX86_BREAKPOINT #define STATUS_WX86_BREAKPOINT 0x4000001F #endif #ifndef DBG_PRINTEXCEPTION_C #define DBG_PRINTEXCEPTION_C 0x40010006 // OutputDebugStringA() call #endif #ifndef DBG_PRINTEXCEPTION_WIDE_C #define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A // OutputDebugStringW() call #endif #ifndef DBG_THREAD_NAME #define DBG_THREAD_NAME 0x406D1388 #endif #define EXCEPTION_CPP_MSC 0xE06D7363 // '?msc' #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 0x19930520 // '?msc' version magic, see ehdata.h #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 0x19930521 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 0x19930522 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1 0x01994000 // '?msc' version magic #define EXCEPTION_CPP_GCC 0x20474343 // ' GCC' #define EXCEPTION_CPP_GCC_UNWIND 0x21474343 // '!GCC' #define EXCEPTION_CPP_GCC_FORCED 0x22474343 // '"GCC' #define EXCEPTION_CLR_FAILURE 0xE0434f4D // 'аCOM' #define EXCEPTION_CPP_BORLAND_BUILDER 0x0EEDFAE6 // Should never occur here #define EXCEPTION_CPP_BORLAND_DELPHI 0x0EEDFADE // Should never occur here #pragma pack (push, 1) struct CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; }; struct CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; }; struct CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; }; struct DATABLOCK_HEADER { DWORD cbSize; DWORD dwSignature; }; struct NT_CONSOLE_PROPS { DATABLOCK_HEADER dbh; WORD wFillAttribute; WORD wPopupFillAttribute; COORD dwScreenBufferSize; COORD dwWindowSize; COORD dwWindowOrigin; DWORD nFont; DWORD nInputBufferSize; COORD dwFontSize; UINT uFontFamily; UINT uFontWeight; WCHAR FaceName[LF_FACESIZE]; UINT uCursorSize; BOOL bFullScreen; BOOL bQuickEdit; BOOL bInsertMode; BOOL bAutoPosition; UINT uHistoryBufferSize; UINT uNumberOfHistoryBuffers; BOOL bHistoryNoDup; COLORREF ColorTable[16]; }; struct FLASHWINFO { UINT cbSize; HWND hwnd; DWORD dwFlags; UINT uCount; DWORD dwTimeout; }; enum TBPFLAG { TBPF_NOPROGRESS = 0x0, TBPF_INDETERMINATE = 0x1, TBPF_NORMAL = 0x2, TBPF_ERROR = 0x4, TBPF_PAUSED = 0x8 }; #pragma pack (pop) const GUID IID_IShellLink = {0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_IShellLinkDataList = {0x45e2b4ae, 0xb1c3, 0x11d0, {0xb9,0x2f,0x00,0xa0,0xc9,0x03,0x12,0xe1}}; const GUID IID_IPersistFile = {0x0000010b, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; const GUID CLSID_TaskbarList = {0x56fdf344, 0xfd6d, 0x11d0, {0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}}; const GUID CLSID_SpVoice = {0x96749377, 0x3391, 0x11d2, {0x9e,0xe3,0x00,0xc0,0x4f,0x79,0x73,0x96}}; const GUID IID_ISpVoice = {0x6c44df74, 0x72b9, 0x4992, {0xa1,0xec,0xef,0x99,0x6e,0x04,0x22,0xd4}}; typedef DWORD NTSTATUS; typedef ULONG_PTR KAFFINITY; typedef LONG KPRIORITY; struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; wchar_t* Buffer; }; struct RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; UNICODE_STRING DosPath; }; struct CURDIR { UNICODE_STRING DosPath; void* Handle; }; struct RTL_USER_PROCESS_PARAMETERS { ULONG AllocationSize; ULONG Size; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; CURDIR CurrentDirectory; UNICODE_STRING DllPath; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; wchar_t* Environment; ULONG dwX; ULONG dwY; ULONG dwXSize; ULONG dwYSize; ULONG dwXCountChars; ULONG dwYCountChars; ULONG dwFillAttribute; ULONG dwFlags; ULONG wShowWindow; UNICODE_STRING WindowTitle; UNICODE_STRING Desktop; UNICODE_STRING ShellInfo; UNICODE_STRING RuntimeInfo; RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; }; struct PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; void* Reserved3[2]; void* Ldr; RTL_USER_PROCESS_PARAMETERS* ProcessParameters; void* Reserved4[3]; void* AtlThunkSListPtr; void* Reserved5; ULONG Reserved6; void* Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; void* Reserved9[45]; BYTE Reserved10[96]; void* PostProcessInitRoutine; BYTE Reserved11[128]; void* Reserved12[1]; ULONG SessionId; }; struct TEB { void* Reserved1[12]; PEB* ProcessEnvironmentBlock; void* Reserved2[399]; BYTE Reserved3[1952]; void* TlsSlots[64]; BYTE Reserved4[8]; void* Reserved5[26]; void* ReservedForOle; void* Reserved6[4]; void* TlsExpansionSlots; }; struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PEB* PebBaseAddress; KAFFINITY AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; }; enum ADDRESS_MODE { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat }; struct ADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; }; struct KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64 Reserved[5]; }; struct STACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; void* FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; }; struct WOW64_FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE RegisterArea[80]; DWORD Cr0NpxState; }; #pragma pack (push, 4) struct WOW64_CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; WOW64_FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[512]; }; #pragma pack (pop) struct SYMBOL_INFO { ULONG SizeOfStruct; ULONG TypeIndex; ULONG64 Reserved[2]; ULONG info; ULONG Size; ULONG64 ModBase; ULONG Flags; ULONG64 Value; ULONG64 Address; ULONG Register; ULONG Scope; ULONG Tag; ULONG NameLen; ULONG MaxNameLen; char Name[1]; }; struct IMAGEHLP_LINE64 { DWORD SizeOfStruct; void* Key; DWORD LineNumber; char* FileName; DWORD64 Address; }; typedef bool (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64) (HANDLE process, DWORD64 baseAddress, void* buffer, DWORD size, DWORD* bytesRead); typedef void* (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64) (HANDLE process, DWORD64 baseAddress); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64) (HANDLE process, DWORD64 address); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64) (HANDLE process, HANDLE thread, ADDRESS64* address); typedef void (*unexpected_handler)(); #pragma pack (push, 4) struct MINIDUMP_THREAD_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; }; struct MINIDUMP_THREAD_EX_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; ULONG64 BackingStoreBase; ULONG64 BackingStoreEnd; }; struct MINIDUMP_MODULE_CALLBACK { wchar_t* FullPath; ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; VS_FIXEDFILEINFO VersionInfo; void* CvRecord; ULONG SizeOfCvRecord; void* MiscRecord; ULONG SizeOfMiscRecord; }; struct MINIDUMP_INCLUDE_THREAD_CALLBACK { ULONG ThreadId; }; struct MINIDUMP_INCLUDE_MODULE_CALLBACK { ULONG64 BaseOfImage; }; struct MINIDUMP_MEMORY_INFO { ULONG64 BaseAddress; ULONG64 AllocationBase; ULONG32 AllocationProtect; ULONG32 __alignment1; ULONG64 RegionSize; ULONG32 State; ULONG32 Protect; ULONG32 Type; ULONG32 __alignment2; }; struct MINIDUMP_USER_STREAM { ULONG32 Type; ULONG BufferSize; void* Buffer; }; struct MINIDUMP_USER_STREAM_INFORMATION { ULONG UserStreamCount; MINIDUMP_USER_STREAM* UserStreamArray; }; struct MINIDUMP_CALLBACK_INPUT { ULONG ProcessId; HANDLE ProcessHandle; ULONG CallbackType; union //-V2514 { MINIDUMP_THREAD_CALLBACK Thread; MINIDUMP_THREAD_EX_CALLBACK ThreadEx; MINIDUMP_MODULE_CALLBACK Module; MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; }; }; struct MINIDUMP_CALLBACK_OUTPUT { union //-V2514 { ULONG ModuleWriteFlags; ULONG ThreadWriteFlags; ULONG SecondaryFlags; struct { ULONG64 MemoryBase; ULONG MemorySize; }; struct { unsigned CheckCancel; unsigned Cancel; }; HANDLE Handle; //-V117 }; struct { MINIDUMP_MEMORY_INFO VmRegion; unsigned Continue; }; HRESULT Status; }; struct MINIDUMP_EXCEPTION_INFORMATION { DWORD ThreadId; EXCEPTION_POINTERS* ExceptionPointers; unsigned ClientPointers; }; typedef int (WINAPI* MINIDUMP_CALLBACK_ROUTINE) (void* param, MINIDUMP_CALLBACK_INPUT* input, MINIDUMP_CALLBACK_OUTPUT* output); struct MINIDUMP_CALLBACK_INFORMATION { MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; void* CallbackParam; }; enum MINIDUMP_TYPE { MiniDumpNormal = 0x00000000, MiniDumpWithDataSegs = 0x00000001, MiniDumpWithFullMemory = 0x00000002, MiniDumpWithHandleData = 0x00000004, MiniDumpFilterMemory = 0x00000008, MiniDumpScanMemory = 0x00000010, MiniDumpWithUnloadedModules = 0x00000020, MiniDumpWithIndirectlyReferencedMemory = 0x00000040, MiniDumpFilterModulePaths = 0x00000080, MiniDumpWithProcessThreadData = 0x00000100, MiniDumpWithPrivateReadWriteMemory = 0x00000200, MiniDumpWithoutOptionalData = 0x00000400, MiniDumpWithFullMemoryInfo = 0x00000800, MiniDumpWithThreadInfo = 0x00001000, MiniDumpWithCodeSegs = 0x00002000, MiniDumpWithoutAuxiliaryState = 0x00004000, MiniDumpWithFullAuxiliaryState = 0x00008000, MiniDumpWithPrivateWriteCopyMemory = 0x00010000, MiniDumpIgnoreInaccessibleMemory = 0x00020000, MiniDumpWithTokenInformation = 0x00040000 }; #ifndef CONTEXT_ALL #define CONTEXT_ALL ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS ) #endif #pragma pack (pop) } // namespace Win32 #endif // TX_COMPILED #define FOREGROUND_BLACK ( 0 ) #define FOREGROUND_CYAN ( FOREGROUND_BLUE | FOREGROUND_GREEN ) #define FOREGROUND_MAGENTA ( FOREGROUND_BLUE | FOREGROUND_RED ) #define FOREGROUND_DARKYELLOW ( FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_LIGHTGRAY ( FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_DARKGRAY ( FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTBLUE ( FOREGROUND_BLUE | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTGREEN ( FOREGROUND_GREEN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTCYAN ( FOREGROUND_CYAN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTRED ( FOREGROUND_RED | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTMAGENTA ( FOREGROUND_MAGENTA | FOREGROUND_INTENSITY ) #define FOREGROUND_YELLOW ( FOREGROUND_DARKYELLOW | FOREGROUND_INTENSITY ) #define FOREGROUND_WHITE ( FOREGROUND_LIGHTGRAY | FOREGROUND_INTENSITY ) #define BACKGROUND_BLACK ( 0 ) #define BACKGROUND_CYAN ( BACKGROUND_BLUE | BACKGROUND_GREEN ) #define BACKGROUND_MAGENTA ( BACKGROUND_BLUE | BACKGROUND_RED ) #define BACKGROUND_DARKYELLOW ( BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_GRAY ( BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_DARKGRAY ( BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTBLUE ( BACKGROUND_BLUE | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTGREEN ( BACKGROUND_GREEN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTCYAN ( BACKGROUND_CYAN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTRED ( BACKGROUND_RED | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTMAGENTA ( BACKGROUND_MAGENTA | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTYELLOW ( BACKGROUND_DARKYELLOW | BACKGROUND_INTENSITY ) #define BACKGROUND_WHITE ( BACKGROUND_DARKGRAY | BACKGROUND_INTENSITY ) //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ There are copies of MSVC compiler built-in predefined definitions, which are wrong in 64-bit mode. // So we have to override them. See: http://stackoverflow.com/questions/39113168 //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< #if defined (_MSC_VER) // MS ABI C++ Exception Layout namespace Win32 { // --------------------------- // #pragma pack (push, 4) // EXCEPTION_RECORD: // +==================================================+ struct ThrowInfo // |... | { // |NumberParameters: 3, 4 or more | __int32 attributes; // |ExceptionInformation[0]: MS signature 0x19930520 | __int32 pmfnUnwind; // |ExceptionInformation[1]: object* thrown | __int32 pForwardCompat; // |ExceptionInformation[2]: ThrowInfo* --------------+---+ __int32 pCatchableTypeArray; // |ExceptionInformation[3]: ImageBase (if params > 3)| | }; // +==================================================+ | // | struct CatchableTypeArray // ThrowInfo: | { // +======================================+ <-------+ __int32 nCatchableTypes; // | ... | __int32 arrayOfCatchableTypes[]; // +-----+-- pCatchableTypeArray (ptr/RVA) | }; // | +======================================+ // | struct CatchableType // | CatchableTypeArray: { // +---> +======================================+ __int32 properties; // | ... | __int32 pType; // +-----+-- arrayOfCatchableTypes[0] (ptr/RVA) | __int32 thisDisplacement[3]; // struct _PMD // | +======================================+ __int32 sizeOrOffset; // | __int32 copyFunction; // | CatchableType: }; // +---> +====================+ // | ... | std::type_info: #pragma pack (pop) // | pType (ptr/RVA) ---+------> +==================+ // | ... | |type_info data | } // namespace Win32 // +====================+ |... | // +==================+ #endif // Similar to __CxxDetectRethrow(), see C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\crtsrc\vcruntime\frame.cpp: #define _TX_MSC__CXX_DETECT_RETHROW( exc ) \ ( \ (exc) && \ (exc) -> ExceptionCode == EXCEPTION_CPP_MSC && \ (exc) -> NumberParameters >= 3 && \ \ ((exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3) && \ \ (exc) -> ExceptionInformation[2] == 0 \ ) #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ The corresponding structures for GCC // // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h // See: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi //----------------------------------------------------------------------------------------------------------------- #if defined (_GCC_VER) #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // GCC ABI C++ Exception layout. A/B are ExceptionInformation[0]. namespace ABI { // -------------------------------------------------------------- // struct __cxa_exception // Case A: "_Unwind_Exception* A" is undependent exception: { // -------------------------------------------------------- union { // struct // __cxa_exception: std::type_info: { // -*--+====================+ +==================+ ::std::type_info* exceptionType; // ^ |exceptionType* -----+---->|type_info data | void (*exceptionDestructor)(void*); // | |... | |... | }; // -1 | | +==================+ struct // | | | { // A >----|--+--------------------+ __cxa_exception* primaryException; // | | |unwindHeader | void (*padding)(); // +1 | | | }; // | | | | }; // V | | | // -*--- +====================+ void (*unexpected_handler)(); // |object | std::terminate_handler terminateHandler; // +--------------------+ // __cxa_exception* nextException; // Case B: "_Unwind_Exception* B" is dependent exception int handlerCount; // (unwindHeader.exception_class & 1 != 0): int handlerSwitchValue; // ----------------------------------------------------- const unsigned char* actionRecord; // const unsigned char* languageSpecificData; // __cxa_exception: __cxa_exception: void* catchTemp; // -*--+====================+ -*--+=================+ void* adjustedPtr; // ^ |primaryException* --+-- ^ |exceptionType* | // | |... | \ | |... | _Unwind_Exception unwindHeader; // -1 | | | | | | }; // | | | | | | | // B >----|--+--------------------+ | -1 +-----------------+ struct __cxa_eh_globals // | | |unwindHeader | | | |unwindHeader | { // +1 | | | | | | | __cxa_exception* caughtExceptions; // | | | | | | | | unsigned int uncaughtExceptions; // V | | | \ | | | }; // -*--- +====================+ -->*--+=================+ // |... | |object | } // namespace ABI // . . | | // +-----------------+ extern "C" ABI::__cxa_eh_globals* __cxa_get_globals(); #endif // TX_COMPILED #endif //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Hand-made IAT. // Some IDEs don't link with these libs by default in console projects, so do sunrise by hand. :( //----------------------------------------------------------------------------------------------------------------- // Hand-made DLLIMPORT helpers #define _TX_DLLIMPORT( lib, retval, name, params ) TX_DLLIMPORT (true, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_OPT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_CRT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, please) void (*_txDllImport (const char dllFileName[], const char funcName[], bool required = true)) (); //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { _TX_DLLIMPORT ("GDI32", HDC, CreateCompatibleDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateCompatibleBitmap, (HDC dc, int width, int height)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetStockObject, (int object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, SelectObject, (HDC dc, HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetCurrentObject, (HDC dc, unsigned objectType)); _TX_DLLIMPORT ("GDI32", int, GetObjectA, (HGDIOBJ obj, int bufsize, void* buffer)); _TX_DLLIMPORT ("GDI32", DWORD, GetObjectType, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", bool, DeleteDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", bool, DeleteObject, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", COLORREF, SetTextColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, SetBkColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", int, SetBkMode, (HDC dc, int bkMode)); _TX_DLLIMPORT ("GDI32", HFONT, CreateFontA, (int height, int width, int escapement, int orientation, int weight, DWORD italic, DWORD underline, DWORD strikeout, DWORD charSet, DWORD outputPrec, DWORD clipPrec, DWORD quality, DWORD pitchAndFamily, const char face[])); _TX_DLLIMPORT ("GDI32", int, EnumFontFamiliesExA, (HDC dc, LPLOGFONT logFont, FONTENUMPROC enumProc, LPARAM lParam, DWORD reserved)); _TX_DLLIMPORT ("GDI32", COLORREF, SetPixel, (HDC dc, int x, int y, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, GetPixel, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", HPEN, CreatePen, (int penStyle, int width, COLORREF color)); _TX_DLLIMPORT ("GDI32", HBRUSH, CreateSolidBrush, (COLORREF color)); _TX_DLLIMPORT ("GDI32", bool, MoveToEx, (HDC dc, int x, int y, POINT* point)); _TX_DLLIMPORT ("GDI32", bool, LineTo, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", bool, Polygon, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Polyline, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, PolyBezier, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Rectangle, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, RoundRect, (HDC dc, int x0, int y0, int x1, int y1, int sizeX, int sizeY)); _TX_DLLIMPORT ("GDI32", bool, Ellipse, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, Arc, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Pie, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Chord, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, TextOutA, (HDC dc, int x, int y, const char string[], int length)); _TX_DLLIMPORT ("GDI32", UINT, SetTextAlign, (HDC dc, unsigned mode)); _TX_DLLIMPORT ("GDI32", bool, GetTextExtentPoint32A, (HDC dc, const char string[], int length, SIZE* size)); _TX_DLLIMPORT ("GDI32", bool, ExtFloodFill, (HDC dc, int x, int y, COLORREF color, unsigned type)); _TX_DLLIMPORT ("GDI32", bool, BitBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, StretchBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, PlgBlt, (HDC dest, const POINT* parallelogram, HDC src, int xSrc, int ySrc, int width, int height, HBITMAP mask, int xMask, int yMask)); _TX_DLLIMPORT ("GDI32", int, SetDIBitsToDevice, (HDC dc, int xDest, int yDest, DWORD width, DWORD height, int xSrc, int ySrc, unsigned startLine, unsigned numLines, const void* data, const BITMAPINFO* info, unsigned colorUse)); _TX_DLLIMPORT ("GDI32", int, GetDIBits, (HDC hdc, HBITMAP hbmp, unsigned uStartScan, unsigned cScanLines, void* lpvBits, BITMAPINFO* lpbi, unsigned usage)); _TX_DLLIMPORT ("GDI32", bool, PatBlt, (HDC dc, int x0, int y0, int width, int height, DWORD rOp)); _TX_DLLIMPORT ("GDI32", int, SetROP2, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", int, SetStretchBltMode, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", DWORD, GdiSetBatchLimit, (DWORD limit)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateDIBSection, (HDC dc, const BITMAPINFO* bmInfo, unsigned colorUsage, void **vBits, HANDLE section, DWORD offset)); _TX_DLLIMPORT ("User32", int, DrawTextA, (HDC dc, const char text[], int length, RECT* rect, unsigned format)); _TX_DLLIMPORT ("User32", HANDLE, LoadImageA, (HINSTANCE inst, const char name[], unsigned type, int sizex, int sizey, unsigned mode)); _TX_DLLIMPORT_OPT ("User32", bool, IsHungAppWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", HWND, GhostWindowFromHungWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", bool, FlashWindowEx, (const FLASHWINFO* flash)); _TX_DLLIMPORT ("WinMM", bool, PlaySound, (const char sound[], HMODULE mod, DWORD mode)); _TX_DLLIMPORT_OPT ("MSImg32", bool, TransparentBlt, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, unsigned transparentColor)); _TX_DLLIMPORT_OPT ("MSImg32", bool, AlphaBlend, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, BLENDFUNCTION blending)); _TX_DLLIMPORT ("Kernel32", void, ExitProcess, (unsigned retcode)); _TX_DLLIMPORT ("Kernel32", bool, TerminateProcess, (HANDLE process, unsigned retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalExit, (int retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalAppExitA, (unsigned action, const char message[])); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetThreadId, (HANDLE thread)); _TX_DLLIMPORT ("Kernel32", HWND, GetConsoleWindow, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetConsoleFont, (HANDLE con, DWORD fontIndex)); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetNumberOfConsoleFonts, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFont, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFO* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", void, RtlCaptureContext, (CONTEXT* contextRecord)); _TX_DLLIMPORT_OPT ("Kernel32", USHORT, RtlCaptureStackBackTrace, (DWORD framesToSkip, DWORD framesToCapture, void** backTrace, DWORD* hash)); _TX_DLLIMPORT_OPT ("Kernel32", void*, AddVectoredExceptionHandler, (unsigned long firstHandler, PVECTORED_EXCEPTION_HANDLER handler)); _TX_DLLIMPORT_OPT ("Kernel32", unsigned, RemoveVectoredExceptionHandler,(void* handler)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetModuleHandleEx, (DWORD flags, const char moduleName[], HMODULE* module)); _TX_DLLIMPORT_OPT ("Kernel32", bool, IsWow64Process, (HANDLE process, int* isWow64Process)); _TX_DLLIMPORT_OPT ("Kernel32", bool, Wow64GetThreadContext, (HANDLE thread, WOW64_CONTEXT* context)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetThreadStackGuarantee, (unsigned long* stackSize)); _TX_DLLIMPORT ("OLE32", HRESULT, CoInitialize, (void*)); _TX_DLLIMPORT ("OLE32", HRESULT, CoCreateInstance, (REFCLSID clsId, IUnknown*, DWORD, REFIID iId, void** value)); _TX_DLLIMPORT ("OLE32", void, CoUninitialize, (void)); _TX_DLLIMPORT ("Shell32", HINSTANCE,ShellExecuteA, (HWND wnd, const char operation[], const char file[], const char parameters[], const char directory[], int showCmd)); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIA, (const char string[], const char search[])); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIW, (const wchar_t string[], const wchar_t search[])); _TX_DLLIMPORT_OPT ("NTDLL", char*, wine_get_version, (void)); _TX_DLLIMPORT ("NTDLL", NTSTATUS, NtQueryInformationProcess, (HANDLE process, int infoClass, void* processInfo, unsigned long szProcessInfo, unsigned long* szReturnInfo)); _TX_DLLIMPORT_CRT ("MSVCRT", void, exit, (int retcode)); _TX_DLLIMPORT_CRT ("MSVCRT", void, _cexit, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _fpreset, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _controlfp, (unsigned control, unsigned mask)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthread, (void (__cdecl* start_address) (void*), unsigned stack_size, void* arglist)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthreadex, (void* security, unsigned stack_size, unsigned (__stdcall* start_address) (void*), void *arglist, unsigned init_flag, unsigned* thread_addr)); _TX_DLLIMPORT_CRT ("MSVCRT", char*, __unDName, (char* outStr, const char* mangledName, int outStrLen, void* (*mallocFunc) (size_t size), void (*freeFunc) (void *pointer), unsigned short flags)); _TX_DLLIMPORT_CRT ("MSVCRT", unexpected_handler, set_unexpected, (unexpected_handler handler)); _TX_DLLIMPORT_OPT ("OpenGL32", HDC, wglGetCurrentDC, (void)); _TX_DLLIMPORT_OPT ("OpenGL32", unsigned, glGetError, (void)); _TX_DLLIMPORT_OPT ("Glu32", const char*, gluErrorString, (unsigned error)); _TX_DLLIMPORT_OPT ("ComDlg32", DWORD, CommDlgExtendedError, (void)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, MiniDumpWriteDump, (HANDLE process, DWORD processId, HANDLE file, MINIDUMP_TYPE dumpType, MINIDUMP_EXCEPTION_INFORMATION* exceptionParam, MINIDUMP_USER_STREAM_INFORMATION* userStreamParam, MINIDUMP_CALLBACK_INFORMATION* callbackParam)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("DbgHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); namespace MinGW { _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("MgwHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); } // namespace MinGW } // namespace Win32 #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal function prototypes, macros and constants // @name Прототипы внутренних функций, макросы и константы //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize(); void _txCleanup(); HWND _txCanvas_CreateWindow (const SIZE* size); bool _txCanvas_OnCREATE (HWND wnd); bool _txCanvas_OnDESTROY (HWND wnd); bool _txCanvas_OnCLOSE (HWND); bool _txCanvas_OnPAINT (HWND wnd); bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down); bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info); bool _txCanvas_OnTIMER (HWND wnd, WPARAM id); bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords); bool _txCanvas_OnMOUSELEAVE (HWND wnd); bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd); bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd); unsigned WINAPI _txCanvas_ThreadProc (void* data); LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard; bool _txBuffer_Delete (HDC* dc); bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC()); HWND _txConsole_Attach(); bool _txConsole_OK() tx_nodiscard; bool _txConsole_Detach (bool activate); bool _txConsole_Draw (HDC dc); bool _txConsole_SetUnicodeFont(); const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra); HWND txCreateExtraWindow (CREATESTRUCT createData); HICON _txCreateTXIcon (int size) tx_nodiscard; int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL, int checkOfs = 0, const wchar_t checkLetters[2] = NULL); int _txPauseBeforeTermination (HWND canvas); int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard; void _txActivateWindow (HWND wnd, unsigned mode); int _txGetInput(); LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); const char* _txPlayVideo_FindVLC() tx_nodiscard; bool _txCreateShortcut (const char shortcutName[], const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL, const char description[] = NULL, int cmdShow = SW_SHOWNORMAL, const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0, COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD)); void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) tx_nodiscard; void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]); const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args); void _txOnTerminate(); void _txOnUnexpected(); void _txOnPureCall(); void _txOnNewHandlerAnsi(); int _txOnNewHandler (size_t size); void _txOnSignal (int signal = 0, int fpe = 0); BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type); void _txOnSecurityError (int code, void*); void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code); int _txOnMatherr (_exception* except); void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned line, uintptr_t); int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line); int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5); int _txOnErrorReport (int type, const char* text, int* ret); int tx_glGetError (int setError = INT_MIN); void _txOnCExit(); void _txOnExit (int retcode); void _txOnFatalExit (int retcode); void _txOnExitProcess (unsigned retcode); void _txOnFatalAppExitA (unsigned action, const char message[]); bool _txOnTerminateProcess (HANDLE process, unsigned retcode); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter); void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc); long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc); long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]); intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]); intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type); intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0, unsigned params = 0, const ULONG_PTR info[] = NULL); void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?", bool readSource = true); const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true, CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread()); int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL, HANDLE thread = GetCurrentThread()); const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false); const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2); bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL, Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL, const char** source = NULL, int context = 2); intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN); bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL); uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL, int useHotPatching = false, HMODULE module = NULL, bool debug = false); bool _txInDll() tx_nodiscard; PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard; bool _txKillProcess (DWORD pid); int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/); bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true); bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid()); IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard; bool _txIsConsoleSubsystem(); const char* _txAppInfo() tx_nodiscard; #if defined (_CLANG_VER) && !defined (_MSC_VER) void _txLibCppDebugFunction (std::__libcpp_debug_info const& info); #endif #endif // TX_COMPILED inline bool _txCanvas_OK () tx_nodiscard; int _txCanvas_SetRefreshLock (int count); const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0, const char msg[] = NULL, ...) tx_printfy (5); bool _txIsBadReadPtr (const void* address); intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3); intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg); bool _txIsTTY (int fd); void txReopenStdio(); #if defined (__CYGWIN__) int _getch(); int _putch (int ch); int _kbhit() tx_nodiscard; #endif //----------------------------------------------------------------------------------------------------------------- // There are macros for __FILE__ and __LINE__ to work properly. #if !defined (NDEBUG) #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \ (assert (cond), true) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Параметр \"%s\" неверен." \ " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка.", #dc), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (TX_ERROR ("\a" "%s" \ "Если вы указали параметр \"%s\", то он неверен.%s", \ (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \ #dc, \ ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка." : "")), 1) ) #else #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #endif //----------------------------------------------------------------------------------------------------------------- // Take action in debug configuration only. // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'( #if !defined (NDEBUG) #define _TX_ON_DEBUG( code ) { code; } #else #define _TX_ON_DEBUG( code ) ; #endif //----------------------------------------------------------------------------------------------------------------- // Invokes an error without location information. "$$" restores TX-related call location context #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__) //----------------------------------------------------------------------------------------------------------------- // Safe call of a function via its pointer #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 ) #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 ) //----------------------------------------------------------------------------------------------------------------- // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x. #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \ !(cond) && GetTickCount() < _t; \ Sleep (_txWindowUpdateInterval)) \ ; \ \ if (!(cond)) \ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); } //----------------------------------------------------------------------------------------------------------------- // Detouring in case of SEH mechanism #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 ) #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; } //----------------------------------------------------------------------------------------------------------------- // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code. #if defined (IN) // #undef IN #endif #if defined (OUT) // #undef OUT #endif //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal global data //! @name Внутренние глобальные данные // // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :) // // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же. // Здесь это сделано только в образовательных целях. // // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс. //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<< const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна _TX_IDM_CONSOLE = 40001, _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas //----------------------------------------------------------------------------------------------------------------- volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize(); volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main() volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT() RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0] HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP), // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock() UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question. int _txConsole = false; // Only first TXLib module in app can own the console bool _txMain = false; // First TXLib wnd opened (closing it terminates program) bool _txIsDll = false; // TXLib module is in DLL volatile bool _txRunning = false; // main() is still running volatile bool _txExit = false; // exit() is active volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE() volatile unsigned _txMouseButtons = 0; volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook(). _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro volatile int _txErrors = 0; // TX_ERROR calls sequental number volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError() volatile long _txSENumber = 0; // SEH exceptions sequental number volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess, (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA, (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp, (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier, (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler, (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace, (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize, (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions, (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64, (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr, (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup, (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64, (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64, (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64, (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext }; volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- extern volatile unsigned _txCanaryFirst; extern volatile unsigned _txCanaryLast; extern volatile HWND _txCanvas_Window; extern volatile unsigned _txCanvas_ThreadId; extern HDC _txCanvas_BackBuf[2]; extern RGBQUAD* _txCanvas_Pixels; extern volatile int _txCanvas_RefreshLock; extern volatile WNDPROC _txAltWndProc; extern volatile bool _txExit; extern volatile int _txOGLError; //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib engine init/check/cleanup //! @name Инициализация/проверка/завершение TXLib //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Early initialization //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize() { if (_txInitialized) return 1; _txInitialized = 1; #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585 #endif #if defined (_TX_ALLOW_TRACE) _txLocLvlSet (1); #endif _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" " "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n"); OutputDebugString ("\n")); _txMainThreadId = GetCurrentThreadId(); _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId); $3 _txIsDll = _txInDll(); $ if (!_txIsDll) { $ _txConsole = ! FindAtom ("_txConsole"); $ (void) AddAtom ("_txConsole"); //-V530 } $ if (_txConsole) { $ _txCheckSourceCP (_TX_CODEPAGE, true); $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ _txOnSignal(); $ if (!*_txLogName) {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); } $ if (!_txIsDll) { $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler)); $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter); } $ ::std::set_terminate (_txOnTerminate); $ ::std::set_new_handler (_txOnNewHandlerAnsi); $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected)); #if defined (_CLANG_VER) && !defined (_MSC_VER) $ ::std::__libcpp_debug_function = _txLibCppDebugFunction; #endif $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true); $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #if defined (_MSC_VER) $ _set_printf_count_output (1); $ _set_new_handler (_txOnNewHandler); $ _set_new_mode (1); #if !defined (_CLANG_VER) $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); $ _CrtSetAllocHook (_txOnAllocHook); $ unsigned mode = _CRTDBG_MODE_FILE; $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0; $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode); $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG); $ _set_abort_behavior (0, _CALL_REPORTFAULT); $ _RTC_SetErrorFunc (_txOnRTCFailure); $ _set_purecall_handler (_txOnPureCall); $ _set_invalid_parameter_handler (_txOnInvalidParam); #endif #if defined (__STDC_LIB_EXT1__) $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi); #endif #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386) $ __setusermatherr (_txOnMatherr); #endif #if !defined (__CYGWIN__) $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR); #endif $ HWND console = _txConsole_Attach(); $ SetWindowTextA (console, txGetModuleFileName (false)); } $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL"); $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL"); $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit); $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit); $ InitializeCriticalSection (&_txCanvas_LockBackBuf); $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted; $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted; $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted; $ Win32::DeleteDC (dc) asserted; $ atexit (_txCleanup); $ if (_txConsole) { $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ tx_fpreset(); $ srand ((unsigned) time (NULL)); //-V202 $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif } $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used" $ return 1; } //----------------------------------------------------------------------------------------------------------------- bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/) { $3 const char* sCodePage = NULL; $ int codePage = 0; $ switch (((unsigned const char*) "А") [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
6880  // | | элемента | X | Y |Шир.|Выс.| окон диалога в MSDN)
6881  //----------------------+----------+-----------+---+---+----+----+---------------------------------------------
6882  // | | | | | | |
6883  {{ txDialog::DIALOG, caption, 0, 0, 0, 240, 85 },
6884  { txDialog::STATIC, text, ID_TEXT_, 10, 10, 150, 40, SS_LEFT },
6885  { txDialog::EDIT, input, ID_INPUT_, 10, 60, 220, 15, ES_LEFT | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP },
6886  { txDialog::BUTTON, "&OK", IDOK, 180, 10, 50, 15, BS_DEFPUSHBUTTON | WS_TABSTOP },
6887  { txDialog::BUTTON, "&Cancel", IDCANCEL, 180, 30, 50, 15, BS_PUSHBUTTON | WS_TABSTOP },
6888  { txDialog::END }};
6889 
6890  //-------------------------------------------------------------------------------------------------------------
6891  // Класс диалога для InputBox. Внутренний, т.к. зачем ему быть внешним.
6892  // Нужен в основном для задания строки ввода (str) и оконной функции диалогового окна, требуемой Win32 (она // построена макросами TX_BEGIN_MESSAGE_MAP и другими). Можно не делать внутреннего класса, но тогда оконную // функцию придется писать в глобальной области видимости, и str объявлять глобально тоже (или передавать ее // адрес через DialogBoxParam и записывать его в класс во время обработки WM_INITDIALOG). //------------------------------------------------------------------------------------------------------------- struct inputDlg : txDialog { char str [1024]; //--------------------------------------------------------------------------------------------------------- inputDlg() : str() {} //--------------------------------------------------------------------------------------------------------- TX_BEGIN_MESSAGE_MAP() // Карта сообщений (на самом деле это начало оконной функции). //-V2525 TX_COMMAND_MAP // Здесь обрабатываются WM_COMMAND (на самом деле это оператор switch). //------------------------------------------------------------------------------------------------- // При нажатии кнопки OK копируем строку из поля ввода в нашу переменную str, т.к. после закрытия // диалога строка ввода умрет и текст уже из нее получить. // Этот макрос на самом деле превращается в case из оператора switch. // _wnd -- это параметр оконной функции, см. определение макроса TX_BEGIN_MESSAGE_MAP(). //------------------------------------------------------------------------------------------------- TX_HANDLE (IDOK) GetDlgItemText (_wnd, ID_INPUT_, str, sizeof (str) - 1); TX_END_MESSAGE_MAP //-V2522 //--------------------------------------------------------------------------------------------------------- // Конец внутреннего класса диалога //--------------------------------------------------------------------------------------------------------- }; //------------------------------------------------------------------------------------------------------------- // Убираем дефайны, чтобы потом не мешали. // От этого они получаются "локального действия", как будто у них была бы область видимости -- функция. На самом // деле это сделано вручную через #undef. Чтобы подчеркнуть их локальную природу, у них имена заканчиваются на _. // Такие дефайны потом не перекосячат весь код после того как, фактически, стали уже не нужны. //------------------------------------------------------------------------------------------------------------- #undef ID_TEXT_ #undef ID_INPUT_ //------------------------------------------------------------------------------------------------------------- // Это статический объект, потому что строка в нем должна жить после завершения функции. //------------------------------------------------------------------------------------------------------------- static inputDlg dlg; //------------------------------------------------------------------------------------------------------------- // Передаем layout и запускаем окно диалога //------------------------------------------------------------------------------------------------------------- dlg.dialogBox (layout); //------------------------------------------------------------------------------------------------------------- // Возвращаем адрес строки из статического объекта. Так можно делать, потому что статический объект не умрет // при выходе из функции и строка в нем, соответственно, тоже. Адрес нестатических переменных передавать // синтаксически можно, но ведет к серьезным ошибкам. //------------------------------------------------------------------------------------------------------------- return dlg.str; } #endif // TX_COMPILED //! @} //} //================================================================================================================= //} //================================================================================================================= //================================================================================================================= //{ TXLIB IMPLEMENTATION // Реализация функций библиотеки //================================================================================================================= //! @cond INTERNAL { //----------------------------------------------------------------------------------------------------------------- //{ The Includes //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< _TX_END_NAMESPACE //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch #pragma warning (disable: 4005) // 'name': macro redefinition #endif #if defined (__STRICT_ANSI__) && defined (__STRICT_ANSI__UNDEFINED) #undef __STRICT_ANSI__ #endif //----------------------------------------------------------------------------------------------------------------- #include <stdarg.h> #include <io.h> #include <fcntl.h> #include <process.h> #include <signal.h> #include <setjmp.h> #include <locale.h> #include <limits.h> #include <stdint.h> #include <map> #include <numeric> #include <exception> #include <stdexcept> #include <tlhelp32.h> #include <shellapi.h> #if defined (_GCC_VER) #include <shlobj.h> #include <cxxabi.h> #include <unwind.h> #endif #if defined (__CYGWIN__) #include <stdarg.h> #include <unistd.h> #include <termios.h> #endif #if defined (_MSC_VER) #include <new.h> #include <shlobj.h> #include <ntstatus.h> #include <crtdbg.h> #include <rtcapi.h> #include <dbghelp.h> #endif #if defined (_GCC_VER) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 #include <inttypes.h> #endif //----------------------------------------------------------------------------------------------------------------- #if defined (TX_USE_SPEAK) //-------------------------------------------------------------------------------------- #include <SAPI.h> // <== ЕСЛИ ЗДЕСЬ ОШИБКА, ТО У ВАС НЕТ ФАЙЛА SAPI.h. No SAPI.h file, TXLib isn't guilty :( #endif //-------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (pop) // MSVC: Restore max level #endif #if defined (__STRICT_ANSI__UNDEFINED) #define __STRICT_ANSI__ // Redefine back #endif //----------------------------------------------------------------------------------------------------------------- _TX_BEGIN_NAMESPACE #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //================================================================================================================= //{ DLL functions import, missing types definitions //! @name Импорт внешних библиотек, определение недостающих типов //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Some of structs, consts and interfaces aren't defined in MinGW some early headers. // Copied from Windows SDK 7.0a. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { #ifndef AC_SRC_ALPHA #define AC_SRC_ALPHA 0x01 #endif #ifndef SMTO_ERRORONEXIT #define SMTO_ERRORONEXIT 0x0020 #endif #ifndef NT_CONSOLE_PROPS_SIG #define NT_CONSOLE_PROPS_SIG 0xA0000002 #endif #ifndef NIIF_INFO #define NIIF_INFO 0x00000001 #define NIIF_WARNING 0x00000002 #define NIIF_ERROR 0x00000003 #endif #ifndef NIF_INFO #define NIF_STATE 0x00000008 #define NIF_INFO 0x00000010 #endif #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004 #endif #ifndef SYMOPT_CASE_INSENSITIVE #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_NO_PROMPTS 0x00080000 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 #define SYMOPT_FAVOR_COMPRESSED 0x00800000 #define SYMOPT_FLAT_DIRECTORY 0x00400000 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 #define SYMOPT_OVERWRITE 0x00100000 #define SYMOPT_DEBUG 0x80000000 #endif // SEH exception codes. For GCC, see http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 64-66. #ifndef STATUS_POSSIBLE_DEADLOCK #define STATUS_POSSIBLE_DEADLOCK 0xC0000194 #endif #ifndef STATUS_FLOAT_MULTIPLE_FAULTS #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4 #endif #ifndef STATUS_STACK_BUFFER_OVERRUN #define STATUS_STACK_BUFFER_OVERRUN 0xC0000409 #endif #ifndef STATUS_ASSERTION_FAILURE #define STATUS_ASSERTION_FAILURE 0xC0000420 #endif #ifndef STATUS_WX86_BREAKPOINT #define STATUS_WX86_BREAKPOINT 0x4000001F #endif #ifndef DBG_PRINTEXCEPTION_C #define DBG_PRINTEXCEPTION_C 0x40010006 // OutputDebugStringA() call #endif #ifndef DBG_PRINTEXCEPTION_WIDE_C #define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A // OutputDebugStringW() call #endif #ifndef DBG_THREAD_NAME #define DBG_THREAD_NAME 0x406D1388 #endif #define EXCEPTION_CPP_MSC 0xE06D7363 // '?msc' #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 0x19930520 // '?msc' version magic, see ehdata.h #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 0x19930521 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 0x19930522 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1 0x01994000 // '?msc' version magic #define EXCEPTION_CPP_GCC 0x20474343 // ' GCC' #define EXCEPTION_CPP_GCC_UNWIND 0x21474343 // '!GCC' #define EXCEPTION_CPP_GCC_FORCED 0x22474343 // '"GCC' #define EXCEPTION_CLR_FAILURE 0xE0434f4D // 'аCOM' #define EXCEPTION_CPP_BORLAND_BUILDER 0x0EEDFAE6 // Should never occur here #define EXCEPTION_CPP_BORLAND_DELPHI 0x0EEDFADE // Should never occur here #pragma pack (push, 1) struct CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; }; struct CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; }; struct CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; }; struct DATABLOCK_HEADER { DWORD cbSize; DWORD dwSignature; }; struct NT_CONSOLE_PROPS { DATABLOCK_HEADER dbh; WORD wFillAttribute; WORD wPopupFillAttribute; COORD dwScreenBufferSize; COORD dwWindowSize; COORD dwWindowOrigin; DWORD nFont; DWORD nInputBufferSize; COORD dwFontSize; UINT uFontFamily; UINT uFontWeight; WCHAR FaceName[LF_FACESIZE]; UINT uCursorSize; BOOL bFullScreen; BOOL bQuickEdit; BOOL bInsertMode; BOOL bAutoPosition; UINT uHistoryBufferSize; UINT uNumberOfHistoryBuffers; BOOL bHistoryNoDup; COLORREF ColorTable[16]; }; struct FLASHWINFO { UINT cbSize; HWND hwnd; DWORD dwFlags; UINT uCount; DWORD dwTimeout; }; enum TBPFLAG { TBPF_NOPROGRESS = 0x0, TBPF_INDETERMINATE = 0x1, TBPF_NORMAL = 0x2, TBPF_ERROR = 0x4, TBPF_PAUSED = 0x8 }; #pragma pack (pop) const GUID IID_IShellLink = {0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_IShellLinkDataList = {0x45e2b4ae, 0xb1c3, 0x11d0, {0xb9,0x2f,0x00,0xa0,0xc9,0x03,0x12,0xe1}}; const GUID IID_IPersistFile = {0x0000010b, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; const GUID CLSID_TaskbarList = {0x56fdf344, 0xfd6d, 0x11d0, {0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}}; const GUID CLSID_SpVoice = {0x96749377, 0x3391, 0x11d2, {0x9e,0xe3,0x00,0xc0,0x4f,0x79,0x73,0x96}}; const GUID IID_ISpVoice = {0x6c44df74, 0x72b9, 0x4992, {0xa1,0xec,0xef,0x99,0x6e,0x04,0x22,0xd4}}; typedef DWORD NTSTATUS; typedef ULONG_PTR KAFFINITY; typedef LONG KPRIORITY; struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; wchar_t* Buffer; }; struct RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; UNICODE_STRING DosPath; }; struct CURDIR { UNICODE_STRING DosPath; void* Handle; }; struct RTL_USER_PROCESS_PARAMETERS { ULONG AllocationSize; ULONG Size; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; CURDIR CurrentDirectory; UNICODE_STRING DllPath; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; wchar_t* Environment; ULONG dwX; ULONG dwY; ULONG dwXSize; ULONG dwYSize; ULONG dwXCountChars; ULONG dwYCountChars; ULONG dwFillAttribute; ULONG dwFlags; ULONG wShowWindow; UNICODE_STRING WindowTitle; UNICODE_STRING Desktop; UNICODE_STRING ShellInfo; UNICODE_STRING RuntimeInfo; RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; }; struct PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; void* Reserved3[2]; void* Ldr; RTL_USER_PROCESS_PARAMETERS* ProcessParameters; void* Reserved4[3]; void* AtlThunkSListPtr; void* Reserved5; ULONG Reserved6; void* Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; void* Reserved9[45]; BYTE Reserved10[96]; void* PostProcessInitRoutine; BYTE Reserved11[128]; void* Reserved12[1]; ULONG SessionId; }; struct TEB { void* Reserved1[12]; PEB* ProcessEnvironmentBlock; void* Reserved2[399]; BYTE Reserved3[1952]; void* TlsSlots[64]; BYTE Reserved4[8]; void* Reserved5[26]; void* ReservedForOle; void* Reserved6[4]; void* TlsExpansionSlots; }; struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PEB* PebBaseAddress; KAFFINITY AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; }; enum ADDRESS_MODE { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat }; struct ADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; }; struct KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64 Reserved[5]; }; struct STACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; void* FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; }; struct WOW64_FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE RegisterArea[80]; DWORD Cr0NpxState; }; #pragma pack (push, 4) struct WOW64_CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; WOW64_FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[512]; }; #pragma pack (pop) struct SYMBOL_INFO { ULONG SizeOfStruct; ULONG TypeIndex; ULONG64 Reserved[2]; ULONG info; ULONG Size; ULONG64 ModBase; ULONG Flags; ULONG64 Value; ULONG64 Address; ULONG Register; ULONG Scope; ULONG Tag; ULONG NameLen; ULONG MaxNameLen; char Name[1]; }; struct IMAGEHLP_LINE64 { DWORD SizeOfStruct; void* Key; DWORD LineNumber; char* FileName; DWORD64 Address; }; typedef bool (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64) (HANDLE process, DWORD64 baseAddress, void* buffer, DWORD size, DWORD* bytesRead); typedef void* (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64) (HANDLE process, DWORD64 baseAddress); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64) (HANDLE process, DWORD64 address); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64) (HANDLE process, HANDLE thread, ADDRESS64* address); typedef void (*unexpected_handler)(); #pragma pack (push, 4) struct MINIDUMP_THREAD_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; }; struct MINIDUMP_THREAD_EX_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; ULONG64 BackingStoreBase; ULONG64 BackingStoreEnd; }; struct MINIDUMP_MODULE_CALLBACK { wchar_t* FullPath; ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; VS_FIXEDFILEINFO VersionInfo; void* CvRecord; ULONG SizeOfCvRecord; void* MiscRecord; ULONG SizeOfMiscRecord; }; struct MINIDUMP_INCLUDE_THREAD_CALLBACK { ULONG ThreadId; }; struct MINIDUMP_INCLUDE_MODULE_CALLBACK { ULONG64 BaseOfImage; }; struct MINIDUMP_MEMORY_INFO { ULONG64 BaseAddress; ULONG64 AllocationBase; ULONG32 AllocationProtect; ULONG32 __alignment1; ULONG64 RegionSize; ULONG32 State; ULONG32 Protect; ULONG32 Type; ULONG32 __alignment2; }; struct MINIDUMP_USER_STREAM { ULONG32 Type; ULONG BufferSize; void* Buffer; }; struct MINIDUMP_USER_STREAM_INFORMATION { ULONG UserStreamCount; MINIDUMP_USER_STREAM* UserStreamArray; }; struct MINIDUMP_CALLBACK_INPUT { ULONG ProcessId; HANDLE ProcessHandle; ULONG CallbackType; union //-V2514 { MINIDUMP_THREAD_CALLBACK Thread; MINIDUMP_THREAD_EX_CALLBACK ThreadEx; MINIDUMP_MODULE_CALLBACK Module; MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; }; }; struct MINIDUMP_CALLBACK_OUTPUT { union //-V2514 { ULONG ModuleWriteFlags; ULONG ThreadWriteFlags; ULONG SecondaryFlags; struct { ULONG64 MemoryBase; ULONG MemorySize; }; struct { unsigned CheckCancel; unsigned Cancel; }; HANDLE Handle; //-V117 }; struct { MINIDUMP_MEMORY_INFO VmRegion; unsigned Continue; }; HRESULT Status; }; struct MINIDUMP_EXCEPTION_INFORMATION { DWORD ThreadId; EXCEPTION_POINTERS* ExceptionPointers; unsigned ClientPointers; }; typedef int (WINAPI* MINIDUMP_CALLBACK_ROUTINE) (void* param, MINIDUMP_CALLBACK_INPUT* input, MINIDUMP_CALLBACK_OUTPUT* output); struct MINIDUMP_CALLBACK_INFORMATION { MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; void* CallbackParam; }; enum MINIDUMP_TYPE { MiniDumpNormal = 0x00000000, MiniDumpWithDataSegs = 0x00000001, MiniDumpWithFullMemory = 0x00000002, MiniDumpWithHandleData = 0x00000004, MiniDumpFilterMemory = 0x00000008, MiniDumpScanMemory = 0x00000010, MiniDumpWithUnloadedModules = 0x00000020, MiniDumpWithIndirectlyReferencedMemory = 0x00000040, MiniDumpFilterModulePaths = 0x00000080, MiniDumpWithProcessThreadData = 0x00000100, MiniDumpWithPrivateReadWriteMemory = 0x00000200, MiniDumpWithoutOptionalData = 0x00000400, MiniDumpWithFullMemoryInfo = 0x00000800, MiniDumpWithThreadInfo = 0x00001000, MiniDumpWithCodeSegs = 0x00002000, MiniDumpWithoutAuxiliaryState = 0x00004000, MiniDumpWithFullAuxiliaryState = 0x00008000, MiniDumpWithPrivateWriteCopyMemory = 0x00010000, MiniDumpIgnoreInaccessibleMemory = 0x00020000, MiniDumpWithTokenInformation = 0x00040000 }; #ifndef CONTEXT_ALL #define CONTEXT_ALL ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS ) #endif #pragma pack (pop) } // namespace Win32 #endif // TX_COMPILED #define FOREGROUND_BLACK ( 0 ) #define FOREGROUND_CYAN ( FOREGROUND_BLUE | FOREGROUND_GREEN ) #define FOREGROUND_MAGENTA ( FOREGROUND_BLUE | FOREGROUND_RED ) #define FOREGROUND_DARKYELLOW ( FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_LIGHTGRAY ( FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_DARKGRAY ( FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTBLUE ( FOREGROUND_BLUE | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTGREEN ( FOREGROUND_GREEN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTCYAN ( FOREGROUND_CYAN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTRED ( FOREGROUND_RED | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTMAGENTA ( FOREGROUND_MAGENTA | FOREGROUND_INTENSITY ) #define FOREGROUND_YELLOW ( FOREGROUND_DARKYELLOW | FOREGROUND_INTENSITY ) #define FOREGROUND_WHITE ( FOREGROUND_LIGHTGRAY | FOREGROUND_INTENSITY ) #define BACKGROUND_BLACK ( 0 ) #define BACKGROUND_CYAN ( BACKGROUND_BLUE | BACKGROUND_GREEN ) #define BACKGROUND_MAGENTA ( BACKGROUND_BLUE | BACKGROUND_RED ) #define BACKGROUND_DARKYELLOW ( BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_GRAY ( BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_DARKGRAY ( BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTBLUE ( BACKGROUND_BLUE | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTGREEN ( BACKGROUND_GREEN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTCYAN ( BACKGROUND_CYAN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTRED ( BACKGROUND_RED | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTMAGENTA ( BACKGROUND_MAGENTA | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTYELLOW ( BACKGROUND_DARKYELLOW | BACKGROUND_INTENSITY ) #define BACKGROUND_WHITE ( BACKGROUND_DARKGRAY | BACKGROUND_INTENSITY ) //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ There are copies of MSVC compiler built-in predefined definitions, which are wrong in 64-bit mode. // So we have to override them. See: http://stackoverflow.com/questions/39113168 //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< #if defined (_MSC_VER) // MS ABI C++ Exception Layout namespace Win32 { // --------------------------- // #pragma pack (push, 4) // EXCEPTION_RECORD: // +==================================================+ struct ThrowInfo // |... | { // |NumberParameters: 3, 4 or more | __int32 attributes; // |ExceptionInformation[0]: MS signature 0x19930520 | __int32 pmfnUnwind; // |ExceptionInformation[1]: object* thrown | __int32 pForwardCompat; // |ExceptionInformation[2]: ThrowInfo* --------------+---+ __int32 pCatchableTypeArray; // |ExceptionInformation[3]: ImageBase (if params > 3)| | }; // +==================================================+ | // | struct CatchableTypeArray // ThrowInfo: | { // +======================================+ <-------+ __int32 nCatchableTypes; // | ... | __int32 arrayOfCatchableTypes[]; // +-----+-- pCatchableTypeArray (ptr/RVA) | }; // | +======================================+ // | struct CatchableType // | CatchableTypeArray: { // +---> +======================================+ __int32 properties; // | ... | __int32 pType; // +-----+-- arrayOfCatchableTypes[0] (ptr/RVA) | __int32 thisDisplacement[3]; // struct _PMD // | +======================================+ __int32 sizeOrOffset; // | __int32 copyFunction; // | CatchableType: }; // +---> +====================+ // | ... | std::type_info: #pragma pack (pop) // | pType (ptr/RVA) ---+------> +==================+ // | ... | |type_info data | } // namespace Win32 // +====================+ |... | // +==================+ #endif // Similar to __CxxDetectRethrow(), see C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\crtsrc\vcruntime\frame.cpp: #define _TX_MSC__CXX_DETECT_RETHROW( exc ) \ ( \ (exc) && \ (exc) -> ExceptionCode == EXCEPTION_CPP_MSC && \ (exc) -> NumberParameters >= 3 && \ \ ((exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3) && \ \ (exc) -> ExceptionInformation[2] == 0 \ ) #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ The corresponding structures for GCC // // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h // See: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi //----------------------------------------------------------------------------------------------------------------- #if defined (_GCC_VER) #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // GCC ABI C++ Exception layout. A/B are ExceptionInformation[0]. namespace ABI { // -------------------------------------------------------------- // struct __cxa_exception // Case A: "_Unwind_Exception* A" is undependent exception: { // -------------------------------------------------------- union { // struct // __cxa_exception: std::type_info: { // -*--+====================+ +==================+ ::std::type_info* exceptionType; // ^ |exceptionType* -----+---->|type_info data | void (*exceptionDestructor)(void*); // | |... | |... | }; // -1 | | +==================+ struct // | | | { // A >----|--+--------------------+ __cxa_exception* primaryException; // | | |unwindHeader | void (*padding)(); // +1 | | | }; // | | | | }; // V | | | // -*--- +====================+ void (*unexpected_handler)(); // |object | std::terminate_handler terminateHandler; // +--------------------+ // __cxa_exception* nextException; // Case B: "_Unwind_Exception* B" is dependent exception int handlerCount; // (unwindHeader.exception_class & 1 != 0): int handlerSwitchValue; // ----------------------------------------------------- const unsigned char* actionRecord; // const unsigned char* languageSpecificData; // __cxa_exception: __cxa_exception: void* catchTemp; // -*--+====================+ -*--+=================+ void* adjustedPtr; // ^ |primaryException* --+-- ^ |exceptionType* | // | |... | \ | |... | _Unwind_Exception unwindHeader; // -1 | | | | | | }; // | | | | | | | // B >----|--+--------------------+ | -1 +-----------------+ struct __cxa_eh_globals // | | |unwindHeader | | | |unwindHeader | { // +1 | | | | | | | __cxa_exception* caughtExceptions; // | | | | | | | | unsigned int uncaughtExceptions; // V | | | \ | | | }; // -*--- +====================+ -->*--+=================+ // |... | |object | } // namespace ABI // . . | | // +-----------------+ extern "C" ABI::__cxa_eh_globals* __cxa_get_globals(); #endif // TX_COMPILED #endif //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Hand-made IAT. // Some IDEs don't link with these libs by default in console projects, so do sunrise by hand. :( //----------------------------------------------------------------------------------------------------------------- // Hand-made DLLIMPORT helpers #define _TX_DLLIMPORT( lib, retval, name, params ) TX_DLLIMPORT (true, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_OPT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_CRT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, please) void (*_txDllImport (const char dllFileName[], const char funcName[], bool required = true)) (); //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { _TX_DLLIMPORT ("GDI32", HDC, CreateCompatibleDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateCompatibleBitmap, (HDC dc, int width, int height)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetStockObject, (int object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, SelectObject, (HDC dc, HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetCurrentObject, (HDC dc, unsigned objectType)); _TX_DLLIMPORT ("GDI32", int, GetObjectA, (HGDIOBJ obj, int bufsize, void* buffer)); _TX_DLLIMPORT ("GDI32", DWORD, GetObjectType, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", bool, DeleteDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", bool, DeleteObject, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", COLORREF, SetTextColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, SetBkColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", int, SetBkMode, (HDC dc, int bkMode)); _TX_DLLIMPORT ("GDI32", HFONT, CreateFontA, (int height, int width, int escapement, int orientation, int weight, DWORD italic, DWORD underline, DWORD strikeout, DWORD charSet, DWORD outputPrec, DWORD clipPrec, DWORD quality, DWORD pitchAndFamily, const char face[])); _TX_DLLIMPORT ("GDI32", int, EnumFontFamiliesExA, (HDC dc, LPLOGFONT logFont, FONTENUMPROC enumProc, LPARAM lParam, DWORD reserved)); _TX_DLLIMPORT ("GDI32", COLORREF, SetPixel, (HDC dc, int x, int y, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, GetPixel, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", HPEN, CreatePen, (int penStyle, int width, COLORREF color)); _TX_DLLIMPORT ("GDI32", HBRUSH, CreateSolidBrush, (COLORREF color)); _TX_DLLIMPORT ("GDI32", bool, MoveToEx, (HDC dc, int x, int y, POINT* point)); _TX_DLLIMPORT ("GDI32", bool, LineTo, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", bool, Polygon, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Polyline, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, PolyBezier, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Rectangle, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, RoundRect, (HDC dc, int x0, int y0, int x1, int y1, int sizeX, int sizeY)); _TX_DLLIMPORT ("GDI32", bool, Ellipse, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, Arc, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Pie, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Chord, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, TextOutA, (HDC dc, int x, int y, const char string[], int length)); _TX_DLLIMPORT ("GDI32", UINT, SetTextAlign, (HDC dc, unsigned mode)); _TX_DLLIMPORT ("GDI32", bool, GetTextExtentPoint32A, (HDC dc, const char string[], int length, SIZE* size)); _TX_DLLIMPORT ("GDI32", bool, ExtFloodFill, (HDC dc, int x, int y, COLORREF color, unsigned type)); _TX_DLLIMPORT ("GDI32", bool, BitBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, StretchBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, PlgBlt, (HDC dest, const POINT* parallelogram, HDC src, int xSrc, int ySrc, int width, int height, HBITMAP mask, int xMask, int yMask)); _TX_DLLIMPORT ("GDI32", int, SetDIBitsToDevice, (HDC dc, int xDest, int yDest, DWORD width, DWORD height, int xSrc, int ySrc, unsigned startLine, unsigned numLines, const void* data, const BITMAPINFO* info, unsigned colorUse)); _TX_DLLIMPORT ("GDI32", int, GetDIBits, (HDC hdc, HBITMAP hbmp, unsigned uStartScan, unsigned cScanLines, void* lpvBits, BITMAPINFO* lpbi, unsigned usage)); _TX_DLLIMPORT ("GDI32", bool, PatBlt, (HDC dc, int x0, int y0, int width, int height, DWORD rOp)); _TX_DLLIMPORT ("GDI32", int, SetROP2, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", int, SetStretchBltMode, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", DWORD, GdiSetBatchLimit, (DWORD limit)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateDIBSection, (HDC dc, const BITMAPINFO* bmInfo, unsigned colorUsage, void **vBits, HANDLE section, DWORD offset)); _TX_DLLIMPORT ("User32", int, DrawTextA, (HDC dc, const char text[], int length, RECT* rect, unsigned format)); _TX_DLLIMPORT ("User32", HANDLE, LoadImageA, (HINSTANCE inst, const char name[], unsigned type, int sizex, int sizey, unsigned mode)); _TX_DLLIMPORT_OPT ("User32", bool, IsHungAppWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", HWND, GhostWindowFromHungWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", bool, FlashWindowEx, (const FLASHWINFO* flash)); _TX_DLLIMPORT ("WinMM", bool, PlaySound, (const char sound[], HMODULE mod, DWORD mode)); _TX_DLLIMPORT_OPT ("MSImg32", bool, TransparentBlt, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, unsigned transparentColor)); _TX_DLLIMPORT_OPT ("MSImg32", bool, AlphaBlend, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, BLENDFUNCTION blending)); _TX_DLLIMPORT ("Kernel32", void, ExitProcess, (unsigned retcode)); _TX_DLLIMPORT ("Kernel32", bool, TerminateProcess, (HANDLE process, unsigned retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalExit, (int retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalAppExitA, (unsigned action, const char message[])); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetThreadId, (HANDLE thread)); _TX_DLLIMPORT ("Kernel32", HWND, GetConsoleWindow, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetConsoleFont, (HANDLE con, DWORD fontIndex)); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetNumberOfConsoleFonts, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFont, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFO* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", void, RtlCaptureContext, (CONTEXT* contextRecord)); _TX_DLLIMPORT_OPT ("Kernel32", USHORT, RtlCaptureStackBackTrace, (DWORD framesToSkip, DWORD framesToCapture, void** backTrace, DWORD* hash)); _TX_DLLIMPORT_OPT ("Kernel32", void*, AddVectoredExceptionHandler, (unsigned long firstHandler, PVECTORED_EXCEPTION_HANDLER handler)); _TX_DLLIMPORT_OPT ("Kernel32", unsigned, RemoveVectoredExceptionHandler,(void* handler)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetModuleHandleEx, (DWORD flags, const char moduleName[], HMODULE* module)); _TX_DLLIMPORT_OPT ("Kernel32", bool, IsWow64Process, (HANDLE process, int* isWow64Process)); _TX_DLLIMPORT_OPT ("Kernel32", bool, Wow64GetThreadContext, (HANDLE thread, WOW64_CONTEXT* context)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetThreadStackGuarantee, (unsigned long* stackSize)); _TX_DLLIMPORT ("OLE32", HRESULT, CoInitialize, (void*)); _TX_DLLIMPORT ("OLE32", HRESULT, CoCreateInstance, (REFCLSID clsId, IUnknown*, DWORD, REFIID iId, void** value)); _TX_DLLIMPORT ("OLE32", void, CoUninitialize, (void)); _TX_DLLIMPORT ("Shell32", HINSTANCE,ShellExecuteA, (HWND wnd, const char operation[], const char file[], const char parameters[], const char directory[], int showCmd)); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIA, (const char string[], const char search[])); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIW, (const wchar_t string[], const wchar_t search[])); _TX_DLLIMPORT_OPT ("NTDLL", char*, wine_get_version, (void)); _TX_DLLIMPORT ("NTDLL", NTSTATUS, NtQueryInformationProcess, (HANDLE process, int infoClass, void* processInfo, unsigned long szProcessInfo, unsigned long* szReturnInfo)); _TX_DLLIMPORT_CRT ("MSVCRT", void, exit, (int retcode)); _TX_DLLIMPORT_CRT ("MSVCRT", void, _cexit, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _fpreset, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _controlfp, (unsigned control, unsigned mask)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthread, (void (__cdecl* start_address) (void*), unsigned stack_size, void* arglist)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthreadex, (void* security, unsigned stack_size, unsigned (__stdcall* start_address) (void*), void *arglist, unsigned init_flag, unsigned* thread_addr)); _TX_DLLIMPORT_CRT ("MSVCRT", char*, __unDName, (char* outStr, const char* mangledName, int outStrLen, void* (*mallocFunc) (size_t size), void (*freeFunc) (void *pointer), unsigned short flags)); _TX_DLLIMPORT_CRT ("MSVCRT", unexpected_handler, set_unexpected, (unexpected_handler handler)); _TX_DLLIMPORT_OPT ("OpenGL32", HDC, wglGetCurrentDC, (void)); _TX_DLLIMPORT_OPT ("OpenGL32", unsigned, glGetError, (void)); _TX_DLLIMPORT_OPT ("Glu32", const char*, gluErrorString, (unsigned error)); _TX_DLLIMPORT_OPT ("ComDlg32", DWORD, CommDlgExtendedError, (void)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, MiniDumpWriteDump, (HANDLE process, DWORD processId, HANDLE file, MINIDUMP_TYPE dumpType, MINIDUMP_EXCEPTION_INFORMATION* exceptionParam, MINIDUMP_USER_STREAM_INFORMATION* userStreamParam, MINIDUMP_CALLBACK_INFORMATION* callbackParam)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("DbgHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); namespace MinGW { _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("MgwHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); } // namespace MinGW } // namespace Win32 #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal function prototypes, macros and constants // @name Прототипы внутренних функций, макросы и константы //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize(); void _txCleanup(); HWND _txCanvas_CreateWindow (const SIZE* size); bool _txCanvas_OnCREATE (HWND wnd); bool _txCanvas_OnDESTROY (HWND wnd); bool _txCanvas_OnCLOSE (HWND); bool _txCanvas_OnPAINT (HWND wnd); bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down); bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info); bool _txCanvas_OnTIMER (HWND wnd, WPARAM id); bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords); bool _txCanvas_OnMOUSELEAVE (HWND wnd); bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd); bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd); unsigned WINAPI _txCanvas_ThreadProc (void* data); LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard; bool _txBuffer_Delete (HDC* dc); bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC()); HWND _txConsole_Attach(); bool _txConsole_OK() tx_nodiscard; bool _txConsole_Detach (bool activate); bool _txConsole_Draw (HDC dc); bool _txConsole_SetUnicodeFont(); const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra); HWND txCreateExtraWindow (CREATESTRUCT createData); HICON _txCreateTXIcon (int size) tx_nodiscard; int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL, int checkOfs = 0, const wchar_t checkLetters[2] = NULL); int _txPauseBeforeTermination (HWND canvas); int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard; void _txActivateWindow (HWND wnd, unsigned mode); int _txGetInput(); LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); const char* _txPlayVideo_FindVLC() tx_nodiscard; bool _txCreateShortcut (const char shortcutName[], const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL, const char description[] = NULL, int cmdShow = SW_SHOWNORMAL, const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0, COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD)); void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) tx_nodiscard; void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]); const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args); void _txOnTerminate(); void _txOnUnexpected(); void _txOnPureCall(); void _txOnNewHandlerAnsi(); int _txOnNewHandler (size_t size); void _txOnSignal (int signal = 0, int fpe = 0); BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type); void _txOnSecurityError (int code, void*); void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code); int _txOnMatherr (_exception* except); void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned line, uintptr_t); int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line); int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5); int _txOnErrorReport (int type, const char* text, int* ret); int tx_glGetError (int setError = INT_MIN); void _txOnCExit(); void _txOnExit (int retcode); void _txOnFatalExit (int retcode); void _txOnExitProcess (unsigned retcode); void _txOnFatalAppExitA (unsigned action, const char message[]); bool _txOnTerminateProcess (HANDLE process, unsigned retcode); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter); void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc); long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc); long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]); intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]); intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type); intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0, unsigned params = 0, const ULONG_PTR info[] = NULL); void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?", bool readSource = true); const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true, CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread()); int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL, HANDLE thread = GetCurrentThread()); const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false); const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2); bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL, Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL, const char** source = NULL, int context = 2); intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN); bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL); uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL, int useHotPatching = false, HMODULE module = NULL, bool debug = false); bool _txInDll() tx_nodiscard; PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard; bool _txKillProcess (DWORD pid); int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/); bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true); bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid()); IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard; bool _txIsConsoleSubsystem(); const char* _txAppInfo() tx_nodiscard; #if defined (_CLANG_VER) && !defined (_MSC_VER) void _txLibCppDebugFunction (std::__libcpp_debug_info const& info); #endif #endif // TX_COMPILED inline bool _txCanvas_OK () tx_nodiscard; int _txCanvas_SetRefreshLock (int count); const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0, const char msg[] = NULL, ...) tx_printfy (5); bool _txIsBadReadPtr (const void* address); intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3); intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg); bool _txIsTTY (int fd); void txReopenStdio(); #if defined (__CYGWIN__) int _getch(); int _putch (int ch); int _kbhit() tx_nodiscard; #endif //----------------------------------------------------------------------------------------------------------------- // There are macros for __FILE__ and __LINE__ to work properly. #if !defined (NDEBUG) #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \ (assert (cond), true) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Параметр \"%s\" неверен." \ " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка.", #dc), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (TX_ERROR ("\a" "%s" \ "Если вы указали параметр \"%s\", то он неверен.%s", \ (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \ #dc, \ ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка." : "")), 1) ) #else #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #endif //----------------------------------------------------------------------------------------------------------------- // Take action in debug configuration only. // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'( #if !defined (NDEBUG) #define _TX_ON_DEBUG( code ) { code; } #else #define _TX_ON_DEBUG( code ) ; #endif //----------------------------------------------------------------------------------------------------------------- // Invokes an error without location information. "$$" restores TX-related call location context #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__) //----------------------------------------------------------------------------------------------------------------- // Safe call of a function via its pointer #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 ) #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 ) //----------------------------------------------------------------------------------------------------------------- // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x. #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \ !(cond) && GetTickCount() < _t; \ Sleep (_txWindowUpdateInterval)) \ ; \ \ if (!(cond)) \ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); } //----------------------------------------------------------------------------------------------------------------- // Detouring in case of SEH mechanism #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 ) #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; } //----------------------------------------------------------------------------------------------------------------- // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code. #if defined (IN) // #undef IN #endif #if defined (OUT) // #undef OUT #endif //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal global data //! @name Внутренние глобальные данные // // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :) // // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же. // Здесь это сделано только в образовательных целях. // // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс. //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<< const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна _TX_IDM_CONSOLE = 40001, _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas //----------------------------------------------------------------------------------------------------------------- volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize(); volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main() volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT() RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0] HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP), // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock() UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question. int _txConsole = false; // Only first TXLib module in app can own the console bool _txMain = false; // First TXLib wnd opened (closing it terminates program) bool _txIsDll = false; // TXLib module is in DLL volatile bool _txRunning = false; // main() is still running volatile bool _txExit = false; // exit() is active volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE() volatile unsigned _txMouseButtons = 0; volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook(). _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro volatile int _txErrors = 0; // TX_ERROR calls sequental number volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError() volatile long _txSENumber = 0; // SEH exceptions sequental number volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess, (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA, (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp, (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier, (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler, (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace, (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize, (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions, (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64, (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr, (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup, (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64, (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64, (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64, (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext }; volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- extern volatile unsigned _txCanaryFirst; extern volatile unsigned _txCanaryLast; extern volatile HWND _txCanvas_Window; extern volatile unsigned _txCanvas_ThreadId; extern HDC _txCanvas_BackBuf[2]; extern RGBQUAD* _txCanvas_Pixels; extern volatile int _txCanvas_RefreshLock; extern volatile WNDPROC _txAltWndProc; extern volatile bool _txExit; extern volatile int _txOGLError; //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib engine init/check/cleanup //! @name Инициализация/проверка/завершение TXLib //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Early initialization //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize() { if (_txInitialized) return 1; _txInitialized = 1; #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585 #endif #if defined (_TX_ALLOW_TRACE) _txLocLvlSet (1); #endif _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" " "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n"); OutputDebugString ("\n")); _txMainThreadId = GetCurrentThreadId(); _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId); $3 _txIsDll = _txInDll(); $ if (!_txIsDll) { $ _txConsole = ! FindAtom ("_txConsole"); $ (void) AddAtom ("_txConsole"); //-V530 } $ if (_txConsole) { $ _txCheckSourceCP (_TX_CODEPAGE, true); $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ _txOnSignal(); $ if (!*_txLogName) {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); } $ if (!_txIsDll) { $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler)); $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter); } $ ::std::set_terminate (_txOnTerminate); $ ::std::set_new_handler (_txOnNewHandlerAnsi); $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected)); #if defined (_CLANG_VER) && !defined (_MSC_VER) $ ::std::__libcpp_debug_function = _txLibCppDebugFunction; #endif $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true); $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #if defined (_MSC_VER) $ _set_printf_count_output (1); $ _set_new_handler (_txOnNewHandler); $ _set_new_mode (1); #if !defined (_CLANG_VER) $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); $ _CrtSetAllocHook (_txOnAllocHook); $ unsigned mode = _CRTDBG_MODE_FILE; $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0; $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode); $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG); $ _set_abort_behavior (0, _CALL_REPORTFAULT); $ _RTC_SetErrorFunc (_txOnRTCFailure); $ _set_purecall_handler (_txOnPureCall); $ _set_invalid_parameter_handler (_txOnInvalidParam); #endif #if defined (__STDC_LIB_EXT1__) $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi); #endif #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386) $ __setusermatherr (_txOnMatherr); #endif #if !defined (__CYGWIN__) $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR); #endif $ HWND console = _txConsole_Attach(); $ SetWindowTextA (console, txGetModuleFileName (false)); } $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL"); $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL"); $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit); $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit); $ InitializeCriticalSection (&_txCanvas_LockBackBuf); $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted; $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted; $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted; $ Win32::DeleteDC (dc) asserted; $ atexit (_txCleanup); $ if (_txConsole) { $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ tx_fpreset(); $ srand ((unsigned) time (NULL)); //-V202 $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif } $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used" $ return 1; } //----------------------------------------------------------------------------------------------------------------- bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/) { $3 const char* sCodePage = NULL; $ int codePage = 0; $ switch (((unsigned const char*) "А") [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
6893  // построена макросами TX_BEGIN_MESSAGE_MAP и другими). Можно не делать внутреннего класса, но тогда оконную
6894  // функцию придется писать в глобальной области видимости, и str объявлять глобально тоже (или передавать ее
6895  // адрес через DialogBoxParam и записывать его в класс во время обработки WM_INITDIALOG).
6896  //-------------------------------------------------------------------------------------------------------------
6897  struct inputDlg : txDialog
6898  {
6899  char str [1024];
6900 
6901  //---------------------------------------------------------------------------------------------------------
6902 
6903  inputDlg() :
6904  str()
6905  {}
6906 
6907  //---------------------------------------------------------------------------------------------------------
6908 
6909  TX_BEGIN_MESSAGE_MAP() // Карта сообщений (на самом деле это начало оконной функции). //-V2525
6910 
6911  TX_COMMAND_MAP // Здесь обрабатываются WM_COMMAND (на самом деле это оператор switch).
6912 
6913  //-------------------------------------------------------------------------------------------------
6914  // При нажатии кнопки OK копируем строку из поля ввода в нашу переменную str, т.к. после закрытия
6915  // диалога строка ввода умрет и текст уже из нее получить.
6916  // Этот макрос на самом деле превращается в case из оператора switch.
6917  // _wnd -- это параметр оконной функции, см. определение макроса TX_BEGIN_MESSAGE_MAP().
6918  //-------------------------------------------------------------------------------------------------
6919 
6920  TX_HANDLE (IDOK) GetDlgItemText (_wnd, ID_INPUT_, str, sizeof (str) - 1);
6921 
6922  TX_END_MESSAGE_MAP //-V2522
6923 
6924  //---------------------------------------------------------------------------------------------------------
6925  // Конец внутреннего класса диалога //--------------------------------------------------------------------------------------------------------- }; //------------------------------------------------------------------------------------------------------------- // Убираем дефайны, чтобы потом не мешали. // От этого они получаются "локального действия", как будто у них была бы область видимости -- функция. На самом // деле это сделано вручную через #undef. Чтобы подчеркнуть их локальную природу, у них имена заканчиваются на _. // Такие дефайны потом не перекосячат весь код после того как, фактически, стали уже не нужны. //------------------------------------------------------------------------------------------------------------- #undef ID_TEXT_ #undef ID_INPUT_ //------------------------------------------------------------------------------------------------------------- // Это статический объект, потому что строка в нем должна жить после завершения функции. //------------------------------------------------------------------------------------------------------------- static inputDlg dlg; //------------------------------------------------------------------------------------------------------------- // Передаем layout и запускаем окно диалога //------------------------------------------------------------------------------------------------------------- dlg.dialogBox (layout); //------------------------------------------------------------------------------------------------------------- // Возвращаем адрес строки из статического объекта. Так можно делать, потому что статический объект не умрет // при выходе из функции и строка в нем, соответственно, тоже. Адрес нестатических переменных передавать // синтаксически можно, но ведет к серьезным ошибкам. //------------------------------------------------------------------------------------------------------------- return dlg.str; } #endif // TX_COMPILED //! @} //} //================================================================================================================= //} //================================================================================================================= //================================================================================================================= //{ TXLIB IMPLEMENTATION // Реализация функций библиотеки //================================================================================================================= //! @cond INTERNAL { //----------------------------------------------------------------------------------------------------------------- //{ The Includes //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< _TX_END_NAMESPACE //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch #pragma warning (disable: 4005) // 'name': macro redefinition #endif #if defined (__STRICT_ANSI__) && defined (__STRICT_ANSI__UNDEFINED) #undef __STRICT_ANSI__ #endif //----------------------------------------------------------------------------------------------------------------- #include <stdarg.h> #include <io.h> #include <fcntl.h> #include <process.h> #include <signal.h> #include <setjmp.h> #include <locale.h> #include <limits.h> #include <stdint.h> #include <map> #include <numeric> #include <exception> #include <stdexcept> #include <tlhelp32.h> #include <shellapi.h> #if defined (_GCC_VER) #include <shlobj.h> #include <cxxabi.h> #include <unwind.h> #endif #if defined (__CYGWIN__) #include <stdarg.h> #include <unistd.h> #include <termios.h> #endif #if defined (_MSC_VER) #include <new.h> #include <shlobj.h> #include <ntstatus.h> #include <crtdbg.h> #include <rtcapi.h> #include <dbghelp.h> #endif #if defined (_GCC_VER) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 #include <inttypes.h> #endif //----------------------------------------------------------------------------------------------------------------- #if defined (TX_USE_SPEAK) //-------------------------------------------------------------------------------------- #include <SAPI.h> // <== ЕСЛИ ЗДЕСЬ ОШИБКА, ТО У ВАС НЕТ ФАЙЛА SAPI.h. No SAPI.h file, TXLib isn't guilty :( #endif //-------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (pop) // MSVC: Restore max level #endif #if defined (__STRICT_ANSI__UNDEFINED) #define __STRICT_ANSI__ // Redefine back #endif //----------------------------------------------------------------------------------------------------------------- _TX_BEGIN_NAMESPACE #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //================================================================================================================= //{ DLL functions import, missing types definitions //! @name Импорт внешних библиотек, определение недостающих типов //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Some of structs, consts and interfaces aren't defined in MinGW some early headers. // Copied from Windows SDK 7.0a. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { #ifndef AC_SRC_ALPHA #define AC_SRC_ALPHA 0x01 #endif #ifndef SMTO_ERRORONEXIT #define SMTO_ERRORONEXIT 0x0020 #endif #ifndef NT_CONSOLE_PROPS_SIG #define NT_CONSOLE_PROPS_SIG 0xA0000002 #endif #ifndef NIIF_INFO #define NIIF_INFO 0x00000001 #define NIIF_WARNING 0x00000002 #define NIIF_ERROR 0x00000003 #endif #ifndef NIF_INFO #define NIF_STATE 0x00000008 #define NIF_INFO 0x00000010 #endif #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004 #endif #ifndef SYMOPT_CASE_INSENSITIVE #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_NO_PROMPTS 0x00080000 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 #define SYMOPT_FAVOR_COMPRESSED 0x00800000 #define SYMOPT_FLAT_DIRECTORY 0x00400000 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 #define SYMOPT_OVERWRITE 0x00100000 #define SYMOPT_DEBUG 0x80000000 #endif // SEH exception codes. For GCC, see http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 64-66. #ifndef STATUS_POSSIBLE_DEADLOCK #define STATUS_POSSIBLE_DEADLOCK 0xC0000194 #endif #ifndef STATUS_FLOAT_MULTIPLE_FAULTS #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4 #endif #ifndef STATUS_STACK_BUFFER_OVERRUN #define STATUS_STACK_BUFFER_OVERRUN 0xC0000409 #endif #ifndef STATUS_ASSERTION_FAILURE #define STATUS_ASSERTION_FAILURE 0xC0000420 #endif #ifndef STATUS_WX86_BREAKPOINT #define STATUS_WX86_BREAKPOINT 0x4000001F #endif #ifndef DBG_PRINTEXCEPTION_C #define DBG_PRINTEXCEPTION_C 0x40010006 // OutputDebugStringA() call #endif #ifndef DBG_PRINTEXCEPTION_WIDE_C #define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A // OutputDebugStringW() call #endif #ifndef DBG_THREAD_NAME #define DBG_THREAD_NAME 0x406D1388 #endif #define EXCEPTION_CPP_MSC 0xE06D7363 // '?msc' #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 0x19930520 // '?msc' version magic, see ehdata.h #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 0x19930521 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 0x19930522 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1 0x01994000 // '?msc' version magic #define EXCEPTION_CPP_GCC 0x20474343 // ' GCC' #define EXCEPTION_CPP_GCC_UNWIND 0x21474343 // '!GCC' #define EXCEPTION_CPP_GCC_FORCED 0x22474343 // '"GCC' #define EXCEPTION_CLR_FAILURE 0xE0434f4D // 'аCOM' #define EXCEPTION_CPP_BORLAND_BUILDER 0x0EEDFAE6 // Should never occur here #define EXCEPTION_CPP_BORLAND_DELPHI 0x0EEDFADE // Should never occur here #pragma pack (push, 1) struct CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; }; struct CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; }; struct CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; }; struct DATABLOCK_HEADER { DWORD cbSize; DWORD dwSignature; }; struct NT_CONSOLE_PROPS { DATABLOCK_HEADER dbh; WORD wFillAttribute; WORD wPopupFillAttribute; COORD dwScreenBufferSize; COORD dwWindowSize; COORD dwWindowOrigin; DWORD nFont; DWORD nInputBufferSize; COORD dwFontSize; UINT uFontFamily; UINT uFontWeight; WCHAR FaceName[LF_FACESIZE]; UINT uCursorSize; BOOL bFullScreen; BOOL bQuickEdit; BOOL bInsertMode; BOOL bAutoPosition; UINT uHistoryBufferSize; UINT uNumberOfHistoryBuffers; BOOL bHistoryNoDup; COLORREF ColorTable[16]; }; struct FLASHWINFO { UINT cbSize; HWND hwnd; DWORD dwFlags; UINT uCount; DWORD dwTimeout; }; enum TBPFLAG { TBPF_NOPROGRESS = 0x0, TBPF_INDETERMINATE = 0x1, TBPF_NORMAL = 0x2, TBPF_ERROR = 0x4, TBPF_PAUSED = 0x8 }; #pragma pack (pop) const GUID IID_IShellLink = {0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_IShellLinkDataList = {0x45e2b4ae, 0xb1c3, 0x11d0, {0xb9,0x2f,0x00,0xa0,0xc9,0x03,0x12,0xe1}}; const GUID IID_IPersistFile = {0x0000010b, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; const GUID CLSID_TaskbarList = {0x56fdf344, 0xfd6d, 0x11d0, {0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}}; const GUID CLSID_SpVoice = {0x96749377, 0x3391, 0x11d2, {0x9e,0xe3,0x00,0xc0,0x4f,0x79,0x73,0x96}}; const GUID IID_ISpVoice = {0x6c44df74, 0x72b9, 0x4992, {0xa1,0xec,0xef,0x99,0x6e,0x04,0x22,0xd4}}; typedef DWORD NTSTATUS; typedef ULONG_PTR KAFFINITY; typedef LONG KPRIORITY; struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; wchar_t* Buffer; }; struct RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; UNICODE_STRING DosPath; }; struct CURDIR { UNICODE_STRING DosPath; void* Handle; }; struct RTL_USER_PROCESS_PARAMETERS { ULONG AllocationSize; ULONG Size; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; CURDIR CurrentDirectory; UNICODE_STRING DllPath; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; wchar_t* Environment; ULONG dwX; ULONG dwY; ULONG dwXSize; ULONG dwYSize; ULONG dwXCountChars; ULONG dwYCountChars; ULONG dwFillAttribute; ULONG dwFlags; ULONG wShowWindow; UNICODE_STRING WindowTitle; UNICODE_STRING Desktop; UNICODE_STRING ShellInfo; UNICODE_STRING RuntimeInfo; RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; }; struct PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; void* Reserved3[2]; void* Ldr; RTL_USER_PROCESS_PARAMETERS* ProcessParameters; void* Reserved4[3]; void* AtlThunkSListPtr; void* Reserved5; ULONG Reserved6; void* Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; void* Reserved9[45]; BYTE Reserved10[96]; void* PostProcessInitRoutine; BYTE Reserved11[128]; void* Reserved12[1]; ULONG SessionId; }; struct TEB { void* Reserved1[12]; PEB* ProcessEnvironmentBlock; void* Reserved2[399]; BYTE Reserved3[1952]; void* TlsSlots[64]; BYTE Reserved4[8]; void* Reserved5[26]; void* ReservedForOle; void* Reserved6[4]; void* TlsExpansionSlots; }; struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PEB* PebBaseAddress; KAFFINITY AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; }; enum ADDRESS_MODE { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat }; struct ADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; }; struct KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64 Reserved[5]; }; struct STACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; void* FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; }; struct WOW64_FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE RegisterArea[80]; DWORD Cr0NpxState; }; #pragma pack (push, 4) struct WOW64_CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; WOW64_FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[512]; }; #pragma pack (pop) struct SYMBOL_INFO { ULONG SizeOfStruct; ULONG TypeIndex; ULONG64 Reserved[2]; ULONG info; ULONG Size; ULONG64 ModBase; ULONG Flags; ULONG64 Value; ULONG64 Address; ULONG Register; ULONG Scope; ULONG Tag; ULONG NameLen; ULONG MaxNameLen; char Name[1]; }; struct IMAGEHLP_LINE64 { DWORD SizeOfStruct; void* Key; DWORD LineNumber; char* FileName; DWORD64 Address; }; typedef bool (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64) (HANDLE process, DWORD64 baseAddress, void* buffer, DWORD size, DWORD* bytesRead); typedef void* (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64) (HANDLE process, DWORD64 baseAddress); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64) (HANDLE process, DWORD64 address); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64) (HANDLE process, HANDLE thread, ADDRESS64* address); typedef void (*unexpected_handler)(); #pragma pack (push, 4) struct MINIDUMP_THREAD_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; }; struct MINIDUMP_THREAD_EX_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; ULONG64 BackingStoreBase; ULONG64 BackingStoreEnd; }; struct MINIDUMP_MODULE_CALLBACK { wchar_t* FullPath; ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; VS_FIXEDFILEINFO VersionInfo; void* CvRecord; ULONG SizeOfCvRecord; void* MiscRecord; ULONG SizeOfMiscRecord; }; struct MINIDUMP_INCLUDE_THREAD_CALLBACK { ULONG ThreadId; }; struct MINIDUMP_INCLUDE_MODULE_CALLBACK { ULONG64 BaseOfImage; }; struct MINIDUMP_MEMORY_INFO { ULONG64 BaseAddress; ULONG64 AllocationBase; ULONG32 AllocationProtect; ULONG32 __alignment1; ULONG64 RegionSize; ULONG32 State; ULONG32 Protect; ULONG32 Type; ULONG32 __alignment2; }; struct MINIDUMP_USER_STREAM { ULONG32 Type; ULONG BufferSize; void* Buffer; }; struct MINIDUMP_USER_STREAM_INFORMATION { ULONG UserStreamCount; MINIDUMP_USER_STREAM* UserStreamArray; }; struct MINIDUMP_CALLBACK_INPUT { ULONG ProcessId; HANDLE ProcessHandle; ULONG CallbackType; union //-V2514 { MINIDUMP_THREAD_CALLBACK Thread; MINIDUMP_THREAD_EX_CALLBACK ThreadEx; MINIDUMP_MODULE_CALLBACK Module; MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; }; }; struct MINIDUMP_CALLBACK_OUTPUT { union //-V2514 { ULONG ModuleWriteFlags; ULONG ThreadWriteFlags; ULONG SecondaryFlags; struct { ULONG64 MemoryBase; ULONG MemorySize; }; struct { unsigned CheckCancel; unsigned Cancel; }; HANDLE Handle; //-V117 }; struct { MINIDUMP_MEMORY_INFO VmRegion; unsigned Continue; }; HRESULT Status; }; struct MINIDUMP_EXCEPTION_INFORMATION { DWORD ThreadId; EXCEPTION_POINTERS* ExceptionPointers; unsigned ClientPointers; }; typedef int (WINAPI* MINIDUMP_CALLBACK_ROUTINE) (void* param, MINIDUMP_CALLBACK_INPUT* input, MINIDUMP_CALLBACK_OUTPUT* output); struct MINIDUMP_CALLBACK_INFORMATION { MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; void* CallbackParam; }; enum MINIDUMP_TYPE { MiniDumpNormal = 0x00000000, MiniDumpWithDataSegs = 0x00000001, MiniDumpWithFullMemory = 0x00000002, MiniDumpWithHandleData = 0x00000004, MiniDumpFilterMemory = 0x00000008, MiniDumpScanMemory = 0x00000010, MiniDumpWithUnloadedModules = 0x00000020, MiniDumpWithIndirectlyReferencedMemory = 0x00000040, MiniDumpFilterModulePaths = 0x00000080, MiniDumpWithProcessThreadData = 0x00000100, MiniDumpWithPrivateReadWriteMemory = 0x00000200, MiniDumpWithoutOptionalData = 0x00000400, MiniDumpWithFullMemoryInfo = 0x00000800, MiniDumpWithThreadInfo = 0x00001000, MiniDumpWithCodeSegs = 0x00002000, MiniDumpWithoutAuxiliaryState = 0x00004000, MiniDumpWithFullAuxiliaryState = 0x00008000, MiniDumpWithPrivateWriteCopyMemory = 0x00010000, MiniDumpIgnoreInaccessibleMemory = 0x00020000, MiniDumpWithTokenInformation = 0x00040000 }; #ifndef CONTEXT_ALL #define CONTEXT_ALL ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS ) #endif #pragma pack (pop) } // namespace Win32 #endif // TX_COMPILED #define FOREGROUND_BLACK ( 0 ) #define FOREGROUND_CYAN ( FOREGROUND_BLUE | FOREGROUND_GREEN ) #define FOREGROUND_MAGENTA ( FOREGROUND_BLUE | FOREGROUND_RED ) #define FOREGROUND_DARKYELLOW ( FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_LIGHTGRAY ( FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_DARKGRAY ( FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTBLUE ( FOREGROUND_BLUE | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTGREEN ( FOREGROUND_GREEN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTCYAN ( FOREGROUND_CYAN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTRED ( FOREGROUND_RED | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTMAGENTA ( FOREGROUND_MAGENTA | FOREGROUND_INTENSITY ) #define FOREGROUND_YELLOW ( FOREGROUND_DARKYELLOW | FOREGROUND_INTENSITY ) #define FOREGROUND_WHITE ( FOREGROUND_LIGHTGRAY | FOREGROUND_INTENSITY ) #define BACKGROUND_BLACK ( 0 ) #define BACKGROUND_CYAN ( BACKGROUND_BLUE | BACKGROUND_GREEN ) #define BACKGROUND_MAGENTA ( BACKGROUND_BLUE | BACKGROUND_RED ) #define BACKGROUND_DARKYELLOW ( BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_GRAY ( BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_DARKGRAY ( BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTBLUE ( BACKGROUND_BLUE | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTGREEN ( BACKGROUND_GREEN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTCYAN ( BACKGROUND_CYAN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTRED ( BACKGROUND_RED | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTMAGENTA ( BACKGROUND_MAGENTA | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTYELLOW ( BACKGROUND_DARKYELLOW | BACKGROUND_INTENSITY ) #define BACKGROUND_WHITE ( BACKGROUND_DARKGRAY | BACKGROUND_INTENSITY ) //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ There are copies of MSVC compiler built-in predefined definitions, which are wrong in 64-bit mode. // So we have to override them. See: http://stackoverflow.com/questions/39113168 //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< #if defined (_MSC_VER) // MS ABI C++ Exception Layout namespace Win32 { // --------------------------- // #pragma pack (push, 4) // EXCEPTION_RECORD: // +==================================================+ struct ThrowInfo // |... | { // |NumberParameters: 3, 4 or more | __int32 attributes; // |ExceptionInformation[0]: MS signature 0x19930520 | __int32 pmfnUnwind; // |ExceptionInformation[1]: object* thrown | __int32 pForwardCompat; // |ExceptionInformation[2]: ThrowInfo* --------------+---+ __int32 pCatchableTypeArray; // |ExceptionInformation[3]: ImageBase (if params > 3)| | }; // +==================================================+ | // | struct CatchableTypeArray // ThrowInfo: | { // +======================================+ <-------+ __int32 nCatchableTypes; // | ... | __int32 arrayOfCatchableTypes[]; // +-----+-- pCatchableTypeArray (ptr/RVA) | }; // | +======================================+ // | struct CatchableType // | CatchableTypeArray: { // +---> +======================================+ __int32 properties; // | ... | __int32 pType; // +-----+-- arrayOfCatchableTypes[0] (ptr/RVA) | __int32 thisDisplacement[3]; // struct _PMD // | +======================================+ __int32 sizeOrOffset; // | __int32 copyFunction; // | CatchableType: }; // +---> +====================+ // | ... | std::type_info: #pragma pack (pop) // | pType (ptr/RVA) ---+------> +==================+ // | ... | |type_info data | } // namespace Win32 // +====================+ |... | // +==================+ #endif // Similar to __CxxDetectRethrow(), see C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\crtsrc\vcruntime\frame.cpp: #define _TX_MSC__CXX_DETECT_RETHROW( exc ) \ ( \ (exc) && \ (exc) -> ExceptionCode == EXCEPTION_CPP_MSC && \ (exc) -> NumberParameters >= 3 && \ \ ((exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3) && \ \ (exc) -> ExceptionInformation[2] == 0 \ ) #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ The corresponding structures for GCC // // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h // See: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi //----------------------------------------------------------------------------------------------------------------- #if defined (_GCC_VER) #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // GCC ABI C++ Exception layout. A/B are ExceptionInformation[0]. namespace ABI { // -------------------------------------------------------------- // struct __cxa_exception // Case A: "_Unwind_Exception* A" is undependent exception: { // -------------------------------------------------------- union { // struct // __cxa_exception: std::type_info: { // -*--+====================+ +==================+ ::std::type_info* exceptionType; // ^ |exceptionType* -----+---->|type_info data | void (*exceptionDestructor)(void*); // | |... | |... | }; // -1 | | +==================+ struct // | | | { // A >----|--+--------------------+ __cxa_exception* primaryException; // | | |unwindHeader | void (*padding)(); // +1 | | | }; // | | | | }; // V | | | // -*--- +====================+ void (*unexpected_handler)(); // |object | std::terminate_handler terminateHandler; // +--------------------+ // __cxa_exception* nextException; // Case B: "_Unwind_Exception* B" is dependent exception int handlerCount; // (unwindHeader.exception_class & 1 != 0): int handlerSwitchValue; // ----------------------------------------------------- const unsigned char* actionRecord; // const unsigned char* languageSpecificData; // __cxa_exception: __cxa_exception: void* catchTemp; // -*--+====================+ -*--+=================+ void* adjustedPtr; // ^ |primaryException* --+-- ^ |exceptionType* | // | |... | \ | |... | _Unwind_Exception unwindHeader; // -1 | | | | | | }; // | | | | | | | // B >----|--+--------------------+ | -1 +-----------------+ struct __cxa_eh_globals // | | |unwindHeader | | | |unwindHeader | { // +1 | | | | | | | __cxa_exception* caughtExceptions; // | | | | | | | | unsigned int uncaughtExceptions; // V | | | \ | | | }; // -*--- +====================+ -->*--+=================+ // |... | |object | } // namespace ABI // . . | | // +-----------------+ extern "C" ABI::__cxa_eh_globals* __cxa_get_globals(); #endif // TX_COMPILED #endif //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Hand-made IAT. // Some IDEs don't link with these libs by default in console projects, so do sunrise by hand. :( //----------------------------------------------------------------------------------------------------------------- // Hand-made DLLIMPORT helpers #define _TX_DLLIMPORT( lib, retval, name, params ) TX_DLLIMPORT (true, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_OPT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_CRT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, please) void (*_txDllImport (const char dllFileName[], const char funcName[], bool required = true)) (); //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { _TX_DLLIMPORT ("GDI32", HDC, CreateCompatibleDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateCompatibleBitmap, (HDC dc, int width, int height)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetStockObject, (int object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, SelectObject, (HDC dc, HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetCurrentObject, (HDC dc, unsigned objectType)); _TX_DLLIMPORT ("GDI32", int, GetObjectA, (HGDIOBJ obj, int bufsize, void* buffer)); _TX_DLLIMPORT ("GDI32", DWORD, GetObjectType, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", bool, DeleteDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", bool, DeleteObject, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", COLORREF, SetTextColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, SetBkColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", int, SetBkMode, (HDC dc, int bkMode)); _TX_DLLIMPORT ("GDI32", HFONT, CreateFontA, (int height, int width, int escapement, int orientation, int weight, DWORD italic, DWORD underline, DWORD strikeout, DWORD charSet, DWORD outputPrec, DWORD clipPrec, DWORD quality, DWORD pitchAndFamily, const char face[])); _TX_DLLIMPORT ("GDI32", int, EnumFontFamiliesExA, (HDC dc, LPLOGFONT logFont, FONTENUMPROC enumProc, LPARAM lParam, DWORD reserved)); _TX_DLLIMPORT ("GDI32", COLORREF, SetPixel, (HDC dc, int x, int y, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, GetPixel, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", HPEN, CreatePen, (int penStyle, int width, COLORREF color)); _TX_DLLIMPORT ("GDI32", HBRUSH, CreateSolidBrush, (COLORREF color)); _TX_DLLIMPORT ("GDI32", bool, MoveToEx, (HDC dc, int x, int y, POINT* point)); _TX_DLLIMPORT ("GDI32", bool, LineTo, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", bool, Polygon, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Polyline, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, PolyBezier, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Rectangle, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, RoundRect, (HDC dc, int x0, int y0, int x1, int y1, int sizeX, int sizeY)); _TX_DLLIMPORT ("GDI32", bool, Ellipse, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, Arc, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Pie, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Chord, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, TextOutA, (HDC dc, int x, int y, const char string[], int length)); _TX_DLLIMPORT ("GDI32", UINT, SetTextAlign, (HDC dc, unsigned mode)); _TX_DLLIMPORT ("GDI32", bool, GetTextExtentPoint32A, (HDC dc, const char string[], int length, SIZE* size)); _TX_DLLIMPORT ("GDI32", bool, ExtFloodFill, (HDC dc, int x, int y, COLORREF color, unsigned type)); _TX_DLLIMPORT ("GDI32", bool, BitBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, StretchBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, PlgBlt, (HDC dest, const POINT* parallelogram, HDC src, int xSrc, int ySrc, int width, int height, HBITMAP mask, int xMask, int yMask)); _TX_DLLIMPORT ("GDI32", int, SetDIBitsToDevice, (HDC dc, int xDest, int yDest, DWORD width, DWORD height, int xSrc, int ySrc, unsigned startLine, unsigned numLines, const void* data, const BITMAPINFO* info, unsigned colorUse)); _TX_DLLIMPORT ("GDI32", int, GetDIBits, (HDC hdc, HBITMAP hbmp, unsigned uStartScan, unsigned cScanLines, void* lpvBits, BITMAPINFO* lpbi, unsigned usage)); _TX_DLLIMPORT ("GDI32", bool, PatBlt, (HDC dc, int x0, int y0, int width, int height, DWORD rOp)); _TX_DLLIMPORT ("GDI32", int, SetROP2, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", int, SetStretchBltMode, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", DWORD, GdiSetBatchLimit, (DWORD limit)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateDIBSection, (HDC dc, const BITMAPINFO* bmInfo, unsigned colorUsage, void **vBits, HANDLE section, DWORD offset)); _TX_DLLIMPORT ("User32", int, DrawTextA, (HDC dc, const char text[], int length, RECT* rect, unsigned format)); _TX_DLLIMPORT ("User32", HANDLE, LoadImageA, (HINSTANCE inst, const char name[], unsigned type, int sizex, int sizey, unsigned mode)); _TX_DLLIMPORT_OPT ("User32", bool, IsHungAppWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", HWND, GhostWindowFromHungWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", bool, FlashWindowEx, (const FLASHWINFO* flash)); _TX_DLLIMPORT ("WinMM", bool, PlaySound, (const char sound[], HMODULE mod, DWORD mode)); _TX_DLLIMPORT_OPT ("MSImg32", bool, TransparentBlt, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, unsigned transparentColor)); _TX_DLLIMPORT_OPT ("MSImg32", bool, AlphaBlend, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, BLENDFUNCTION blending)); _TX_DLLIMPORT ("Kernel32", void, ExitProcess, (unsigned retcode)); _TX_DLLIMPORT ("Kernel32", bool, TerminateProcess, (HANDLE process, unsigned retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalExit, (int retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalAppExitA, (unsigned action, const char message[])); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetThreadId, (HANDLE thread)); _TX_DLLIMPORT ("Kernel32", HWND, GetConsoleWindow, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetConsoleFont, (HANDLE con, DWORD fontIndex)); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetNumberOfConsoleFonts, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFont, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFO* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", void, RtlCaptureContext, (CONTEXT* contextRecord)); _TX_DLLIMPORT_OPT ("Kernel32", USHORT, RtlCaptureStackBackTrace, (DWORD framesToSkip, DWORD framesToCapture, void** backTrace, DWORD* hash)); _TX_DLLIMPORT_OPT ("Kernel32", void*, AddVectoredExceptionHandler, (unsigned long firstHandler, PVECTORED_EXCEPTION_HANDLER handler)); _TX_DLLIMPORT_OPT ("Kernel32", unsigned, RemoveVectoredExceptionHandler,(void* handler)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetModuleHandleEx, (DWORD flags, const char moduleName[], HMODULE* module)); _TX_DLLIMPORT_OPT ("Kernel32", bool, IsWow64Process, (HANDLE process, int* isWow64Process)); _TX_DLLIMPORT_OPT ("Kernel32", bool, Wow64GetThreadContext, (HANDLE thread, WOW64_CONTEXT* context)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetThreadStackGuarantee, (unsigned long* stackSize)); _TX_DLLIMPORT ("OLE32", HRESULT, CoInitialize, (void*)); _TX_DLLIMPORT ("OLE32", HRESULT, CoCreateInstance, (REFCLSID clsId, IUnknown*, DWORD, REFIID iId, void** value)); _TX_DLLIMPORT ("OLE32", void, CoUninitialize, (void)); _TX_DLLIMPORT ("Shell32", HINSTANCE,ShellExecuteA, (HWND wnd, const char operation[], const char file[], const char parameters[], const char directory[], int showCmd)); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIA, (const char string[], const char search[])); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIW, (const wchar_t string[], const wchar_t search[])); _TX_DLLIMPORT_OPT ("NTDLL", char*, wine_get_version, (void)); _TX_DLLIMPORT ("NTDLL", NTSTATUS, NtQueryInformationProcess, (HANDLE process, int infoClass, void* processInfo, unsigned long szProcessInfo, unsigned long* szReturnInfo)); _TX_DLLIMPORT_CRT ("MSVCRT", void, exit, (int retcode)); _TX_DLLIMPORT_CRT ("MSVCRT", void, _cexit, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _fpreset, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _controlfp, (unsigned control, unsigned mask)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthread, (void (__cdecl* start_address) (void*), unsigned stack_size, void* arglist)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthreadex, (void* security, unsigned stack_size, unsigned (__stdcall* start_address) (void*), void *arglist, unsigned init_flag, unsigned* thread_addr)); _TX_DLLIMPORT_CRT ("MSVCRT", char*, __unDName, (char* outStr, const char* mangledName, int outStrLen, void* (*mallocFunc) (size_t size), void (*freeFunc) (void *pointer), unsigned short flags)); _TX_DLLIMPORT_CRT ("MSVCRT", unexpected_handler, set_unexpected, (unexpected_handler handler)); _TX_DLLIMPORT_OPT ("OpenGL32", HDC, wglGetCurrentDC, (void)); _TX_DLLIMPORT_OPT ("OpenGL32", unsigned, glGetError, (void)); _TX_DLLIMPORT_OPT ("Glu32", const char*, gluErrorString, (unsigned error)); _TX_DLLIMPORT_OPT ("ComDlg32", DWORD, CommDlgExtendedError, (void)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, MiniDumpWriteDump, (HANDLE process, DWORD processId, HANDLE file, MINIDUMP_TYPE dumpType, MINIDUMP_EXCEPTION_INFORMATION* exceptionParam, MINIDUMP_USER_STREAM_INFORMATION* userStreamParam, MINIDUMP_CALLBACK_INFORMATION* callbackParam)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("DbgHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); namespace MinGW { _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("MgwHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); } // namespace MinGW } // namespace Win32 #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal function prototypes, macros and constants // @name Прототипы внутренних функций, макросы и константы //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize(); void _txCleanup(); HWND _txCanvas_CreateWindow (const SIZE* size); bool _txCanvas_OnCREATE (HWND wnd); bool _txCanvas_OnDESTROY (HWND wnd); bool _txCanvas_OnCLOSE (HWND); bool _txCanvas_OnPAINT (HWND wnd); bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down); bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info); bool _txCanvas_OnTIMER (HWND wnd, WPARAM id); bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords); bool _txCanvas_OnMOUSELEAVE (HWND wnd); bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd); bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd); unsigned WINAPI _txCanvas_ThreadProc (void* data); LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard; bool _txBuffer_Delete (HDC* dc); bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC()); HWND _txConsole_Attach(); bool _txConsole_OK() tx_nodiscard; bool _txConsole_Detach (bool activate); bool _txConsole_Draw (HDC dc); bool _txConsole_SetUnicodeFont(); const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra); HWND txCreateExtraWindow (CREATESTRUCT createData); HICON _txCreateTXIcon (int size) tx_nodiscard; int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL, int checkOfs = 0, const wchar_t checkLetters[2] = NULL); int _txPauseBeforeTermination (HWND canvas); int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard; void _txActivateWindow (HWND wnd, unsigned mode); int _txGetInput(); LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); const char* _txPlayVideo_FindVLC() tx_nodiscard; bool _txCreateShortcut (const char shortcutName[], const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL, const char description[] = NULL, int cmdShow = SW_SHOWNORMAL, const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0, COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD)); void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) tx_nodiscard; void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]); const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args); void _txOnTerminate(); void _txOnUnexpected(); void _txOnPureCall(); void _txOnNewHandlerAnsi(); int _txOnNewHandler (size_t size); void _txOnSignal (int signal = 0, int fpe = 0); BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type); void _txOnSecurityError (int code, void*); void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code); int _txOnMatherr (_exception* except); void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned line, uintptr_t); int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line); int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5); int _txOnErrorReport (int type, const char* text, int* ret); int tx_glGetError (int setError = INT_MIN); void _txOnCExit(); void _txOnExit (int retcode); void _txOnFatalExit (int retcode); void _txOnExitProcess (unsigned retcode); void _txOnFatalAppExitA (unsigned action, const char message[]); bool _txOnTerminateProcess (HANDLE process, unsigned retcode); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter); void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc); long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc); long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]); intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]); intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type); intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0, unsigned params = 0, const ULONG_PTR info[] = NULL); void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?", bool readSource = true); const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true, CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread()); int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL, HANDLE thread = GetCurrentThread()); const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false); const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2); bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL, Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL, const char** source = NULL, int context = 2); intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN); bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL); uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL, int useHotPatching = false, HMODULE module = NULL, bool debug = false); bool _txInDll() tx_nodiscard; PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard; bool _txKillProcess (DWORD pid); int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/); bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true); bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid()); IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard; bool _txIsConsoleSubsystem(); const char* _txAppInfo() tx_nodiscard; #if defined (_CLANG_VER) && !defined (_MSC_VER) void _txLibCppDebugFunction (std::__libcpp_debug_info const& info); #endif #endif // TX_COMPILED inline bool _txCanvas_OK () tx_nodiscard; int _txCanvas_SetRefreshLock (int count); const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0, const char msg[] = NULL, ...) tx_printfy (5); bool _txIsBadReadPtr (const void* address); intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3); intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg); bool _txIsTTY (int fd); void txReopenStdio(); #if defined (__CYGWIN__) int _getch(); int _putch (int ch); int _kbhit() tx_nodiscard; #endif //----------------------------------------------------------------------------------------------------------------- // There are macros for __FILE__ and __LINE__ to work properly. #if !defined (NDEBUG) #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \ (assert (cond), true) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Параметр \"%s\" неверен." \ " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка.", #dc), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (TX_ERROR ("\a" "%s" \ "Если вы указали параметр \"%s\", то он неверен.%s", \ (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \ #dc, \ ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка." : "")), 1) ) #else #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #endif //----------------------------------------------------------------------------------------------------------------- // Take action in debug configuration only. // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'( #if !defined (NDEBUG) #define _TX_ON_DEBUG( code ) { code; } #else #define _TX_ON_DEBUG( code ) ; #endif //----------------------------------------------------------------------------------------------------------------- // Invokes an error without location information. "$$" restores TX-related call location context #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__) //----------------------------------------------------------------------------------------------------------------- // Safe call of a function via its pointer #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 ) #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 ) //----------------------------------------------------------------------------------------------------------------- // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x. #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \ !(cond) && GetTickCount() < _t; \ Sleep (_txWindowUpdateInterval)) \ ; \ \ if (!(cond)) \ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); } //----------------------------------------------------------------------------------------------------------------- // Detouring in case of SEH mechanism #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 ) #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; } //----------------------------------------------------------------------------------------------------------------- // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code. #if defined (IN) // #undef IN #endif #if defined (OUT) // #undef OUT #endif //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal global data //! @name Внутренние глобальные данные // // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :) // // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же. // Здесь это сделано только в образовательных целях. // // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс. //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<< const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна _TX_IDM_CONSOLE = 40001, _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas //----------------------------------------------------------------------------------------------------------------- volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize(); volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main() volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT() RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0] HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP), // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock() UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question. int _txConsole = false; // Only first TXLib module in app can own the console bool _txMain = false; // First TXLib wnd opened (closing it terminates program) bool _txIsDll = false; // TXLib module is in DLL volatile bool _txRunning = false; // main() is still running volatile bool _txExit = false; // exit() is active volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE() volatile unsigned _txMouseButtons = 0; volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook(). _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro volatile int _txErrors = 0; // TX_ERROR calls sequental number volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError() volatile long _txSENumber = 0; // SEH exceptions sequental number volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess, (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA, (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp, (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier, (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler, (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace, (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize, (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions, (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64, (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr, (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup, (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64, (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64, (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64, (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext }; volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- extern volatile unsigned _txCanaryFirst; extern volatile unsigned _txCanaryLast; extern volatile HWND _txCanvas_Window; extern volatile unsigned _txCanvas_ThreadId; extern HDC _txCanvas_BackBuf[2]; extern RGBQUAD* _txCanvas_Pixels; extern volatile int _txCanvas_RefreshLock; extern volatile WNDPROC _txAltWndProc; extern volatile bool _txExit; extern volatile int _txOGLError; //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib engine init/check/cleanup //! @name Инициализация/проверка/завершение TXLib //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Early initialization //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize() { if (_txInitialized) return 1; _txInitialized = 1; #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585 #endif #if defined (_TX_ALLOW_TRACE) _txLocLvlSet (1); #endif _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" " "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n"); OutputDebugString ("\n")); _txMainThreadId = GetCurrentThreadId(); _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId); $3 _txIsDll = _txInDll(); $ if (!_txIsDll) { $ _txConsole = ! FindAtom ("_txConsole"); $ (void) AddAtom ("_txConsole"); //-V530 } $ if (_txConsole) { $ _txCheckSourceCP (_TX_CODEPAGE, true); $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ _txOnSignal(); $ if (!*_txLogName) {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); } $ if (!_txIsDll) { $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler)); $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter); } $ ::std::set_terminate (_txOnTerminate); $ ::std::set_new_handler (_txOnNewHandlerAnsi); $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected)); #if defined (_CLANG_VER) && !defined (_MSC_VER) $ ::std::__libcpp_debug_function = _txLibCppDebugFunction; #endif $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true); $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #if defined (_MSC_VER) $ _set_printf_count_output (1); $ _set_new_handler (_txOnNewHandler); $ _set_new_mode (1); #if !defined (_CLANG_VER) $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); $ _CrtSetAllocHook (_txOnAllocHook); $ unsigned mode = _CRTDBG_MODE_FILE; $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0; $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode); $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG); $ _set_abort_behavior (0, _CALL_REPORTFAULT); $ _RTC_SetErrorFunc (_txOnRTCFailure); $ _set_purecall_handler (_txOnPureCall); $ _set_invalid_parameter_handler (_txOnInvalidParam); #endif #if defined (__STDC_LIB_EXT1__) $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi); #endif #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386) $ __setusermatherr (_txOnMatherr); #endif #if !defined (__CYGWIN__) $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR); #endif $ HWND console = _txConsole_Attach(); $ SetWindowTextA (console, txGetModuleFileName (false)); } $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL"); $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL"); $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit); $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit); $ InitializeCriticalSection (&_txCanvas_LockBackBuf); $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted; $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted; $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted; $ Win32::DeleteDC (dc) asserted; $ atexit (_txCleanup); $ if (_txConsole) { $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ tx_fpreset(); $ srand ((unsigned) time (NULL)); //-V202 $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif } $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used" $ return 1; } //----------------------------------------------------------------------------------------------------------------- bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/) { $3 const char* sCodePage = NULL; $ int codePage = 0; $ switch (((unsigned const char*) "А") [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
6926  //---------------------------------------------------------------------------------------------------------
6927  };
6928 
6929  //-------------------------------------------------------------------------------------------------------------
6930  // Убираем дефайны, чтобы потом не мешали.
6931  // От этого они получаются "локального действия", как будто у них была бы область видимости -- функция. На самом // деле это сделано вручную через #undef. Чтобы подчеркнуть их локальную природу, у них имена заканчиваются на _. // Такие дефайны потом не перекосячат весь код после того как, фактически, стали уже не нужны. //------------------------------------------------------------------------------------------------------------- #undef ID_TEXT_ #undef ID_INPUT_ //------------------------------------------------------------------------------------------------------------- // Это статический объект, потому что строка в нем должна жить после завершения функции. //------------------------------------------------------------------------------------------------------------- static inputDlg dlg; //------------------------------------------------------------------------------------------------------------- // Передаем layout и запускаем окно диалога //------------------------------------------------------------------------------------------------------------- dlg.dialogBox (layout); //------------------------------------------------------------------------------------------------------------- // Возвращаем адрес строки из статического объекта. Так можно делать, потому что статический объект не умрет // при выходе из функции и строка в нем, соответственно, тоже. Адрес нестатических переменных передавать // синтаксически можно, но ведет к серьезным ошибкам. //------------------------------------------------------------------------------------------------------------- return dlg.str; } #endif // TX_COMPILED //! @} //} //================================================================================================================= //} //================================================================================================================= //================================================================================================================= //{ TXLIB IMPLEMENTATION // Реализация функций библиотеки //================================================================================================================= //! @cond INTERNAL { //----------------------------------------------------------------------------------------------------------------- //{ The Includes //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< _TX_END_NAMESPACE //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch #pragma warning (disable: 4005) // 'name': macro redefinition #endif #if defined (__STRICT_ANSI__) && defined (__STRICT_ANSI__UNDEFINED) #undef __STRICT_ANSI__ #endif //----------------------------------------------------------------------------------------------------------------- #include <stdarg.h> #include <io.h> #include <fcntl.h> #include <process.h> #include <signal.h> #include <setjmp.h> #include <locale.h> #include <limits.h> #include <stdint.h> #include <map> #include <numeric> #include <exception> #include <stdexcept> #include <tlhelp32.h> #include <shellapi.h> #if defined (_GCC_VER) #include <shlobj.h> #include <cxxabi.h> #include <unwind.h> #endif #if defined (__CYGWIN__) #include <stdarg.h> #include <unistd.h> #include <termios.h> #endif #if defined (_MSC_VER) #include <new.h> #include <shlobj.h> #include <ntstatus.h> #include <crtdbg.h> #include <rtcapi.h> #include <dbghelp.h> #endif #if defined (_GCC_VER) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 #include <inttypes.h> #endif //----------------------------------------------------------------------------------------------------------------- #if defined (TX_USE_SPEAK) //-------------------------------------------------------------------------------------- #include <SAPI.h> // <== ЕСЛИ ЗДЕСЬ ОШИБКА, ТО У ВАС НЕТ ФАЙЛА SAPI.h. No SAPI.h file, TXLib isn't guilty :( #endif //-------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (pop) // MSVC: Restore max level #endif #if defined (__STRICT_ANSI__UNDEFINED) #define __STRICT_ANSI__ // Redefine back #endif //----------------------------------------------------------------------------------------------------------------- _TX_BEGIN_NAMESPACE #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //================================================================================================================= //{ DLL functions import, missing types definitions //! @name Импорт внешних библиотек, определение недостающих типов //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Some of structs, consts and interfaces aren't defined in MinGW some early headers. // Copied from Windows SDK 7.0a. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { #ifndef AC_SRC_ALPHA #define AC_SRC_ALPHA 0x01 #endif #ifndef SMTO_ERRORONEXIT #define SMTO_ERRORONEXIT 0x0020 #endif #ifndef NT_CONSOLE_PROPS_SIG #define NT_CONSOLE_PROPS_SIG 0xA0000002 #endif #ifndef NIIF_INFO #define NIIF_INFO 0x00000001 #define NIIF_WARNING 0x00000002 #define NIIF_ERROR 0x00000003 #endif #ifndef NIF_INFO #define NIF_STATE 0x00000008 #define NIF_INFO 0x00000010 #endif #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004 #endif #ifndef SYMOPT_CASE_INSENSITIVE #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_NO_PROMPTS 0x00080000 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 #define SYMOPT_FAVOR_COMPRESSED 0x00800000 #define SYMOPT_FLAT_DIRECTORY 0x00400000 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 #define SYMOPT_OVERWRITE 0x00100000 #define SYMOPT_DEBUG 0x80000000 #endif // SEH exception codes. For GCC, see http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 64-66. #ifndef STATUS_POSSIBLE_DEADLOCK #define STATUS_POSSIBLE_DEADLOCK 0xC0000194 #endif #ifndef STATUS_FLOAT_MULTIPLE_FAULTS #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4 #endif #ifndef STATUS_STACK_BUFFER_OVERRUN #define STATUS_STACK_BUFFER_OVERRUN 0xC0000409 #endif #ifndef STATUS_ASSERTION_FAILURE #define STATUS_ASSERTION_FAILURE 0xC0000420 #endif #ifndef STATUS_WX86_BREAKPOINT #define STATUS_WX86_BREAKPOINT 0x4000001F #endif #ifndef DBG_PRINTEXCEPTION_C #define DBG_PRINTEXCEPTION_C 0x40010006 // OutputDebugStringA() call #endif #ifndef DBG_PRINTEXCEPTION_WIDE_C #define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A // OutputDebugStringW() call #endif #ifndef DBG_THREAD_NAME #define DBG_THREAD_NAME 0x406D1388 #endif #define EXCEPTION_CPP_MSC 0xE06D7363 // '?msc' #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 0x19930520 // '?msc' version magic, see ehdata.h #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 0x19930521 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 0x19930522 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1 0x01994000 // '?msc' version magic #define EXCEPTION_CPP_GCC 0x20474343 // ' GCC' #define EXCEPTION_CPP_GCC_UNWIND 0x21474343 // '!GCC' #define EXCEPTION_CPP_GCC_FORCED 0x22474343 // '"GCC' #define EXCEPTION_CLR_FAILURE 0xE0434f4D // 'аCOM' #define EXCEPTION_CPP_BORLAND_BUILDER 0x0EEDFAE6 // Should never occur here #define EXCEPTION_CPP_BORLAND_DELPHI 0x0EEDFADE // Should never occur here #pragma pack (push, 1) struct CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; }; struct CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; }; struct CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; }; struct DATABLOCK_HEADER { DWORD cbSize; DWORD dwSignature; }; struct NT_CONSOLE_PROPS { DATABLOCK_HEADER dbh; WORD wFillAttribute; WORD wPopupFillAttribute; COORD dwScreenBufferSize; COORD dwWindowSize; COORD dwWindowOrigin; DWORD nFont; DWORD nInputBufferSize; COORD dwFontSize; UINT uFontFamily; UINT uFontWeight; WCHAR FaceName[LF_FACESIZE]; UINT uCursorSize; BOOL bFullScreen; BOOL bQuickEdit; BOOL bInsertMode; BOOL bAutoPosition; UINT uHistoryBufferSize; UINT uNumberOfHistoryBuffers; BOOL bHistoryNoDup; COLORREF ColorTable[16]; }; struct FLASHWINFO { UINT cbSize; HWND hwnd; DWORD dwFlags; UINT uCount; DWORD dwTimeout; }; enum TBPFLAG { TBPF_NOPROGRESS = 0x0, TBPF_INDETERMINATE = 0x1, TBPF_NORMAL = 0x2, TBPF_ERROR = 0x4, TBPF_PAUSED = 0x8 }; #pragma pack (pop) const GUID IID_IShellLink = {0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_IShellLinkDataList = {0x45e2b4ae, 0xb1c3, 0x11d0, {0xb9,0x2f,0x00,0xa0,0xc9,0x03,0x12,0xe1}}; const GUID IID_IPersistFile = {0x0000010b, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; const GUID CLSID_TaskbarList = {0x56fdf344, 0xfd6d, 0x11d0, {0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}}; const GUID CLSID_SpVoice = {0x96749377, 0x3391, 0x11d2, {0x9e,0xe3,0x00,0xc0,0x4f,0x79,0x73,0x96}}; const GUID IID_ISpVoice = {0x6c44df74, 0x72b9, 0x4992, {0xa1,0xec,0xef,0x99,0x6e,0x04,0x22,0xd4}}; typedef DWORD NTSTATUS; typedef ULONG_PTR KAFFINITY; typedef LONG KPRIORITY; struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; wchar_t* Buffer; }; struct RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; UNICODE_STRING DosPath; }; struct CURDIR { UNICODE_STRING DosPath; void* Handle; }; struct RTL_USER_PROCESS_PARAMETERS { ULONG AllocationSize; ULONG Size; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; CURDIR CurrentDirectory; UNICODE_STRING DllPath; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; wchar_t* Environment; ULONG dwX; ULONG dwY; ULONG dwXSize; ULONG dwYSize; ULONG dwXCountChars; ULONG dwYCountChars; ULONG dwFillAttribute; ULONG dwFlags; ULONG wShowWindow; UNICODE_STRING WindowTitle; UNICODE_STRING Desktop; UNICODE_STRING ShellInfo; UNICODE_STRING RuntimeInfo; RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; }; struct PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; void* Reserved3[2]; void* Ldr; RTL_USER_PROCESS_PARAMETERS* ProcessParameters; void* Reserved4[3]; void* AtlThunkSListPtr; void* Reserved5; ULONG Reserved6; void* Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; void* Reserved9[45]; BYTE Reserved10[96]; void* PostProcessInitRoutine; BYTE Reserved11[128]; void* Reserved12[1]; ULONG SessionId; }; struct TEB { void* Reserved1[12]; PEB* ProcessEnvironmentBlock; void* Reserved2[399]; BYTE Reserved3[1952]; void* TlsSlots[64]; BYTE Reserved4[8]; void* Reserved5[26]; void* ReservedForOle; void* Reserved6[4]; void* TlsExpansionSlots; }; struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PEB* PebBaseAddress; KAFFINITY AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; }; enum ADDRESS_MODE { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat }; struct ADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; }; struct KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64 Reserved[5]; }; struct STACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; void* FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; }; struct WOW64_FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE RegisterArea[80]; DWORD Cr0NpxState; }; #pragma pack (push, 4) struct WOW64_CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; WOW64_FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[512]; }; #pragma pack (pop) struct SYMBOL_INFO { ULONG SizeOfStruct; ULONG TypeIndex; ULONG64 Reserved[2]; ULONG info; ULONG Size; ULONG64 ModBase; ULONG Flags; ULONG64 Value; ULONG64 Address; ULONG Register; ULONG Scope; ULONG Tag; ULONG NameLen; ULONG MaxNameLen; char Name[1]; }; struct IMAGEHLP_LINE64 { DWORD SizeOfStruct; void* Key; DWORD LineNumber; char* FileName; DWORD64 Address; }; typedef bool (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64) (HANDLE process, DWORD64 baseAddress, void* buffer, DWORD size, DWORD* bytesRead); typedef void* (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64) (HANDLE process, DWORD64 baseAddress); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64) (HANDLE process, DWORD64 address); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64) (HANDLE process, HANDLE thread, ADDRESS64* address); typedef void (*unexpected_handler)(); #pragma pack (push, 4) struct MINIDUMP_THREAD_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; }; struct MINIDUMP_THREAD_EX_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; ULONG64 BackingStoreBase; ULONG64 BackingStoreEnd; }; struct MINIDUMP_MODULE_CALLBACK { wchar_t* FullPath; ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; VS_FIXEDFILEINFO VersionInfo; void* CvRecord; ULONG SizeOfCvRecord; void* MiscRecord; ULONG SizeOfMiscRecord; }; struct MINIDUMP_INCLUDE_THREAD_CALLBACK { ULONG ThreadId; }; struct MINIDUMP_INCLUDE_MODULE_CALLBACK { ULONG64 BaseOfImage; }; struct MINIDUMP_MEMORY_INFO { ULONG64 BaseAddress; ULONG64 AllocationBase; ULONG32 AllocationProtect; ULONG32 __alignment1; ULONG64 RegionSize; ULONG32 State; ULONG32 Protect; ULONG32 Type; ULONG32 __alignment2; }; struct MINIDUMP_USER_STREAM { ULONG32 Type; ULONG BufferSize; void* Buffer; }; struct MINIDUMP_USER_STREAM_INFORMATION { ULONG UserStreamCount; MINIDUMP_USER_STREAM* UserStreamArray; }; struct MINIDUMP_CALLBACK_INPUT { ULONG ProcessId; HANDLE ProcessHandle; ULONG CallbackType; union //-V2514 { MINIDUMP_THREAD_CALLBACK Thread; MINIDUMP_THREAD_EX_CALLBACK ThreadEx; MINIDUMP_MODULE_CALLBACK Module; MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; }; }; struct MINIDUMP_CALLBACK_OUTPUT { union //-V2514 { ULONG ModuleWriteFlags; ULONG ThreadWriteFlags; ULONG SecondaryFlags; struct { ULONG64 MemoryBase; ULONG MemorySize; }; struct { unsigned CheckCancel; unsigned Cancel; }; HANDLE Handle; //-V117 }; struct { MINIDUMP_MEMORY_INFO VmRegion; unsigned Continue; }; HRESULT Status; }; struct MINIDUMP_EXCEPTION_INFORMATION { DWORD ThreadId; EXCEPTION_POINTERS* ExceptionPointers; unsigned ClientPointers; }; typedef int (WINAPI* MINIDUMP_CALLBACK_ROUTINE) (void* param, MINIDUMP_CALLBACK_INPUT* input, MINIDUMP_CALLBACK_OUTPUT* output); struct MINIDUMP_CALLBACK_INFORMATION { MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; void* CallbackParam; }; enum MINIDUMP_TYPE { MiniDumpNormal = 0x00000000, MiniDumpWithDataSegs = 0x00000001, MiniDumpWithFullMemory = 0x00000002, MiniDumpWithHandleData = 0x00000004, MiniDumpFilterMemory = 0x00000008, MiniDumpScanMemory = 0x00000010, MiniDumpWithUnloadedModules = 0x00000020, MiniDumpWithIndirectlyReferencedMemory = 0x00000040, MiniDumpFilterModulePaths = 0x00000080, MiniDumpWithProcessThreadData = 0x00000100, MiniDumpWithPrivateReadWriteMemory = 0x00000200, MiniDumpWithoutOptionalData = 0x00000400, MiniDumpWithFullMemoryInfo = 0x00000800, MiniDumpWithThreadInfo = 0x00001000, MiniDumpWithCodeSegs = 0x00002000, MiniDumpWithoutAuxiliaryState = 0x00004000, MiniDumpWithFullAuxiliaryState = 0x00008000, MiniDumpWithPrivateWriteCopyMemory = 0x00010000, MiniDumpIgnoreInaccessibleMemory = 0x00020000, MiniDumpWithTokenInformation = 0x00040000 }; #ifndef CONTEXT_ALL #define CONTEXT_ALL ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS ) #endif #pragma pack (pop) } // namespace Win32 #endif // TX_COMPILED #define FOREGROUND_BLACK ( 0 ) #define FOREGROUND_CYAN ( FOREGROUND_BLUE | FOREGROUND_GREEN ) #define FOREGROUND_MAGENTA ( FOREGROUND_BLUE | FOREGROUND_RED ) #define FOREGROUND_DARKYELLOW ( FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_LIGHTGRAY ( FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_DARKGRAY ( FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTBLUE ( FOREGROUND_BLUE | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTGREEN ( FOREGROUND_GREEN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTCYAN ( FOREGROUND_CYAN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTRED ( FOREGROUND_RED | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTMAGENTA ( FOREGROUND_MAGENTA | FOREGROUND_INTENSITY ) #define FOREGROUND_YELLOW ( FOREGROUND_DARKYELLOW | FOREGROUND_INTENSITY ) #define FOREGROUND_WHITE ( FOREGROUND_LIGHTGRAY | FOREGROUND_INTENSITY ) #define BACKGROUND_BLACK ( 0 ) #define BACKGROUND_CYAN ( BACKGROUND_BLUE | BACKGROUND_GREEN ) #define BACKGROUND_MAGENTA ( BACKGROUND_BLUE | BACKGROUND_RED ) #define BACKGROUND_DARKYELLOW ( BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_GRAY ( BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_DARKGRAY ( BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTBLUE ( BACKGROUND_BLUE | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTGREEN ( BACKGROUND_GREEN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTCYAN ( BACKGROUND_CYAN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTRED ( BACKGROUND_RED | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTMAGENTA ( BACKGROUND_MAGENTA | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTYELLOW ( BACKGROUND_DARKYELLOW | BACKGROUND_INTENSITY ) #define BACKGROUND_WHITE ( BACKGROUND_DARKGRAY | BACKGROUND_INTENSITY ) //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ There are copies of MSVC compiler built-in predefined definitions, which are wrong in 64-bit mode. // So we have to override them. See: http://stackoverflow.com/questions/39113168 //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< #if defined (_MSC_VER) // MS ABI C++ Exception Layout namespace Win32 { // --------------------------- // #pragma pack (push, 4) // EXCEPTION_RECORD: // +==================================================+ struct ThrowInfo // |... | { // |NumberParameters: 3, 4 or more | __int32 attributes; // |ExceptionInformation[0]: MS signature 0x19930520 | __int32 pmfnUnwind; // |ExceptionInformation[1]: object* thrown | __int32 pForwardCompat; // |ExceptionInformation[2]: ThrowInfo* --------------+---+ __int32 pCatchableTypeArray; // |ExceptionInformation[3]: ImageBase (if params > 3)| | }; // +==================================================+ | // | struct CatchableTypeArray // ThrowInfo: | { // +======================================+ <-------+ __int32 nCatchableTypes; // | ... | __int32 arrayOfCatchableTypes[]; // +-----+-- pCatchableTypeArray (ptr/RVA) | }; // | +======================================+ // | struct CatchableType // | CatchableTypeArray: { // +---> +======================================+ __int32 properties; // | ... | __int32 pType; // +-----+-- arrayOfCatchableTypes[0] (ptr/RVA) | __int32 thisDisplacement[3]; // struct _PMD // | +======================================+ __int32 sizeOrOffset; // | __int32 copyFunction; // | CatchableType: }; // +---> +====================+ // | ... | std::type_info: #pragma pack (pop) // | pType (ptr/RVA) ---+------> +==================+ // | ... | |type_info data | } // namespace Win32 // +====================+ |... | // +==================+ #endif // Similar to __CxxDetectRethrow(), see C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\crtsrc\vcruntime\frame.cpp: #define _TX_MSC__CXX_DETECT_RETHROW( exc ) \ ( \ (exc) && \ (exc) -> ExceptionCode == EXCEPTION_CPP_MSC && \ (exc) -> NumberParameters >= 3 && \ \ ((exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3) && \ \ (exc) -> ExceptionInformation[2] == 0 \ ) #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ The corresponding structures for GCC // // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h // See: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi //----------------------------------------------------------------------------------------------------------------- #if defined (_GCC_VER) #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // GCC ABI C++ Exception layout. A/B are ExceptionInformation[0]. namespace ABI { // -------------------------------------------------------------- // struct __cxa_exception // Case A: "_Unwind_Exception* A" is undependent exception: { // -------------------------------------------------------- union { // struct // __cxa_exception: std::type_info: { // -*--+====================+ +==================+ ::std::type_info* exceptionType; // ^ |exceptionType* -----+---->|type_info data | void (*exceptionDestructor)(void*); // | |... | |... | }; // -1 | | +==================+ struct // | | | { // A >----|--+--------------------+ __cxa_exception* primaryException; // | | |unwindHeader | void (*padding)(); // +1 | | | }; // | | | | }; // V | | | // -*--- +====================+ void (*unexpected_handler)(); // |object | std::terminate_handler terminateHandler; // +--------------------+ // __cxa_exception* nextException; // Case B: "_Unwind_Exception* B" is dependent exception int handlerCount; // (unwindHeader.exception_class & 1 != 0): int handlerSwitchValue; // ----------------------------------------------------- const unsigned char* actionRecord; // const unsigned char* languageSpecificData; // __cxa_exception: __cxa_exception: void* catchTemp; // -*--+====================+ -*--+=================+ void* adjustedPtr; // ^ |primaryException* --+-- ^ |exceptionType* | // | |... | \ | |... | _Unwind_Exception unwindHeader; // -1 | | | | | | }; // | | | | | | | // B >----|--+--------------------+ | -1 +-----------------+ struct __cxa_eh_globals // | | |unwindHeader | | | |unwindHeader | { // +1 | | | | | | | __cxa_exception* caughtExceptions; // | | | | | | | | unsigned int uncaughtExceptions; // V | | | \ | | | }; // -*--- +====================+ -->*--+=================+ // |... | |object | } // namespace ABI // . . | | // +-----------------+ extern "C" ABI::__cxa_eh_globals* __cxa_get_globals(); #endif // TX_COMPILED #endif //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Hand-made IAT. // Some IDEs don't link with these libs by default in console projects, so do sunrise by hand. :( //----------------------------------------------------------------------------------------------------------------- // Hand-made DLLIMPORT helpers #define _TX_DLLIMPORT( lib, retval, name, params ) TX_DLLIMPORT (true, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_OPT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_CRT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, please) void (*_txDllImport (const char dllFileName[], const char funcName[], bool required = true)) (); //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { _TX_DLLIMPORT ("GDI32", HDC, CreateCompatibleDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateCompatibleBitmap, (HDC dc, int width, int height)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetStockObject, (int object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, SelectObject, (HDC dc, HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetCurrentObject, (HDC dc, unsigned objectType)); _TX_DLLIMPORT ("GDI32", int, GetObjectA, (HGDIOBJ obj, int bufsize, void* buffer)); _TX_DLLIMPORT ("GDI32", DWORD, GetObjectType, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", bool, DeleteDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", bool, DeleteObject, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", COLORREF, SetTextColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, SetBkColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", int, SetBkMode, (HDC dc, int bkMode)); _TX_DLLIMPORT ("GDI32", HFONT, CreateFontA, (int height, int width, int escapement, int orientation, int weight, DWORD italic, DWORD underline, DWORD strikeout, DWORD charSet, DWORD outputPrec, DWORD clipPrec, DWORD quality, DWORD pitchAndFamily, const char face[])); _TX_DLLIMPORT ("GDI32", int, EnumFontFamiliesExA, (HDC dc, LPLOGFONT logFont, FONTENUMPROC enumProc, LPARAM lParam, DWORD reserved)); _TX_DLLIMPORT ("GDI32", COLORREF, SetPixel, (HDC dc, int x, int y, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, GetPixel, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", HPEN, CreatePen, (int penStyle, int width, COLORREF color)); _TX_DLLIMPORT ("GDI32", HBRUSH, CreateSolidBrush, (COLORREF color)); _TX_DLLIMPORT ("GDI32", bool, MoveToEx, (HDC dc, int x, int y, POINT* point)); _TX_DLLIMPORT ("GDI32", bool, LineTo, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", bool, Polygon, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Polyline, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, PolyBezier, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Rectangle, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, RoundRect, (HDC dc, int x0, int y0, int x1, int y1, int sizeX, int sizeY)); _TX_DLLIMPORT ("GDI32", bool, Ellipse, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, Arc, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Pie, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Chord, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, TextOutA, (HDC dc, int x, int y, const char string[], int length)); _TX_DLLIMPORT ("GDI32", UINT, SetTextAlign, (HDC dc, unsigned mode)); _TX_DLLIMPORT ("GDI32", bool, GetTextExtentPoint32A, (HDC dc, const char string[], int length, SIZE* size)); _TX_DLLIMPORT ("GDI32", bool, ExtFloodFill, (HDC dc, int x, int y, COLORREF color, unsigned type)); _TX_DLLIMPORT ("GDI32", bool, BitBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, StretchBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, PlgBlt, (HDC dest, const POINT* parallelogram, HDC src, int xSrc, int ySrc, int width, int height, HBITMAP mask, int xMask, int yMask)); _TX_DLLIMPORT ("GDI32", int, SetDIBitsToDevice, (HDC dc, int xDest, int yDest, DWORD width, DWORD height, int xSrc, int ySrc, unsigned startLine, unsigned numLines, const void* data, const BITMAPINFO* info, unsigned colorUse)); _TX_DLLIMPORT ("GDI32", int, GetDIBits, (HDC hdc, HBITMAP hbmp, unsigned uStartScan, unsigned cScanLines, void* lpvBits, BITMAPINFO* lpbi, unsigned usage)); _TX_DLLIMPORT ("GDI32", bool, PatBlt, (HDC dc, int x0, int y0, int width, int height, DWORD rOp)); _TX_DLLIMPORT ("GDI32", int, SetROP2, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", int, SetStretchBltMode, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", DWORD, GdiSetBatchLimit, (DWORD limit)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateDIBSection, (HDC dc, const BITMAPINFO* bmInfo, unsigned colorUsage, void **vBits, HANDLE section, DWORD offset)); _TX_DLLIMPORT ("User32", int, DrawTextA, (HDC dc, const char text[], int length, RECT* rect, unsigned format)); _TX_DLLIMPORT ("User32", HANDLE, LoadImageA, (HINSTANCE inst, const char name[], unsigned type, int sizex, int sizey, unsigned mode)); _TX_DLLIMPORT_OPT ("User32", bool, IsHungAppWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", HWND, GhostWindowFromHungWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", bool, FlashWindowEx, (const FLASHWINFO* flash)); _TX_DLLIMPORT ("WinMM", bool, PlaySound, (const char sound[], HMODULE mod, DWORD mode)); _TX_DLLIMPORT_OPT ("MSImg32", bool, TransparentBlt, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, unsigned transparentColor)); _TX_DLLIMPORT_OPT ("MSImg32", bool, AlphaBlend, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, BLENDFUNCTION blending)); _TX_DLLIMPORT ("Kernel32", void, ExitProcess, (unsigned retcode)); _TX_DLLIMPORT ("Kernel32", bool, TerminateProcess, (HANDLE process, unsigned retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalExit, (int retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalAppExitA, (unsigned action, const char message[])); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetThreadId, (HANDLE thread)); _TX_DLLIMPORT ("Kernel32", HWND, GetConsoleWindow, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetConsoleFont, (HANDLE con, DWORD fontIndex)); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetNumberOfConsoleFonts, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFont, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFO* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", void, RtlCaptureContext, (CONTEXT* contextRecord)); _TX_DLLIMPORT_OPT ("Kernel32", USHORT, RtlCaptureStackBackTrace, (DWORD framesToSkip, DWORD framesToCapture, void** backTrace, DWORD* hash)); _TX_DLLIMPORT_OPT ("Kernel32", void*, AddVectoredExceptionHandler, (unsigned long firstHandler, PVECTORED_EXCEPTION_HANDLER handler)); _TX_DLLIMPORT_OPT ("Kernel32", unsigned, RemoveVectoredExceptionHandler,(void* handler)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetModuleHandleEx, (DWORD flags, const char moduleName[], HMODULE* module)); _TX_DLLIMPORT_OPT ("Kernel32", bool, IsWow64Process, (HANDLE process, int* isWow64Process)); _TX_DLLIMPORT_OPT ("Kernel32", bool, Wow64GetThreadContext, (HANDLE thread, WOW64_CONTEXT* context)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetThreadStackGuarantee, (unsigned long* stackSize)); _TX_DLLIMPORT ("OLE32", HRESULT, CoInitialize, (void*)); _TX_DLLIMPORT ("OLE32", HRESULT, CoCreateInstance, (REFCLSID clsId, IUnknown*, DWORD, REFIID iId, void** value)); _TX_DLLIMPORT ("OLE32", void, CoUninitialize, (void)); _TX_DLLIMPORT ("Shell32", HINSTANCE,ShellExecuteA, (HWND wnd, const char operation[], const char file[], const char parameters[], const char directory[], int showCmd)); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIA, (const char string[], const char search[])); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIW, (const wchar_t string[], const wchar_t search[])); _TX_DLLIMPORT_OPT ("NTDLL", char*, wine_get_version, (void)); _TX_DLLIMPORT ("NTDLL", NTSTATUS, NtQueryInformationProcess, (HANDLE process, int infoClass, void* processInfo, unsigned long szProcessInfo, unsigned long* szReturnInfo)); _TX_DLLIMPORT_CRT ("MSVCRT", void, exit, (int retcode)); _TX_DLLIMPORT_CRT ("MSVCRT", void, _cexit, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _fpreset, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _controlfp, (unsigned control, unsigned mask)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthread, (void (__cdecl* start_address) (void*), unsigned stack_size, void* arglist)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthreadex, (void* security, unsigned stack_size, unsigned (__stdcall* start_address) (void*), void *arglist, unsigned init_flag, unsigned* thread_addr)); _TX_DLLIMPORT_CRT ("MSVCRT", char*, __unDName, (char* outStr, const char* mangledName, int outStrLen, void* (*mallocFunc) (size_t size), void (*freeFunc) (void *pointer), unsigned short flags)); _TX_DLLIMPORT_CRT ("MSVCRT", unexpected_handler, set_unexpected, (unexpected_handler handler)); _TX_DLLIMPORT_OPT ("OpenGL32", HDC, wglGetCurrentDC, (void)); _TX_DLLIMPORT_OPT ("OpenGL32", unsigned, glGetError, (void)); _TX_DLLIMPORT_OPT ("Glu32", const char*, gluErrorString, (unsigned error)); _TX_DLLIMPORT_OPT ("ComDlg32", DWORD, CommDlgExtendedError, (void)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, MiniDumpWriteDump, (HANDLE process, DWORD processId, HANDLE file, MINIDUMP_TYPE dumpType, MINIDUMP_EXCEPTION_INFORMATION* exceptionParam, MINIDUMP_USER_STREAM_INFORMATION* userStreamParam, MINIDUMP_CALLBACK_INFORMATION* callbackParam)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("DbgHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); namespace MinGW { _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("MgwHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); } // namespace MinGW } // namespace Win32 #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal function prototypes, macros and constants // @name Прототипы внутренних функций, макросы и константы //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize(); void _txCleanup(); HWND _txCanvas_CreateWindow (const SIZE* size); bool _txCanvas_OnCREATE (HWND wnd); bool _txCanvas_OnDESTROY (HWND wnd); bool _txCanvas_OnCLOSE (HWND); bool _txCanvas_OnPAINT (HWND wnd); bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down); bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info); bool _txCanvas_OnTIMER (HWND wnd, WPARAM id); bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords); bool _txCanvas_OnMOUSELEAVE (HWND wnd); bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd); bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd); unsigned WINAPI _txCanvas_ThreadProc (void* data); LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard; bool _txBuffer_Delete (HDC* dc); bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC()); HWND _txConsole_Attach(); bool _txConsole_OK() tx_nodiscard; bool _txConsole_Detach (bool activate); bool _txConsole_Draw (HDC dc); bool _txConsole_SetUnicodeFont(); const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra); HWND txCreateExtraWindow (CREATESTRUCT createData); HICON _txCreateTXIcon (int size) tx_nodiscard; int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL, int checkOfs = 0, const wchar_t checkLetters[2] = NULL); int _txPauseBeforeTermination (HWND canvas); int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard; void _txActivateWindow (HWND wnd, unsigned mode); int _txGetInput(); LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); const char* _txPlayVideo_FindVLC() tx_nodiscard; bool _txCreateShortcut (const char shortcutName[], const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL, const char description[] = NULL, int cmdShow = SW_SHOWNORMAL, const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0, COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD)); void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) tx_nodiscard; void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]); const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args); void _txOnTerminate(); void _txOnUnexpected(); void _txOnPureCall(); void _txOnNewHandlerAnsi(); int _txOnNewHandler (size_t size); void _txOnSignal (int signal = 0, int fpe = 0); BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type); void _txOnSecurityError (int code, void*); void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code); int _txOnMatherr (_exception* except); void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned line, uintptr_t); int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line); int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5); int _txOnErrorReport (int type, const char* text, int* ret); int tx_glGetError (int setError = INT_MIN); void _txOnCExit(); void _txOnExit (int retcode); void _txOnFatalExit (int retcode); void _txOnExitProcess (unsigned retcode); void _txOnFatalAppExitA (unsigned action, const char message[]); bool _txOnTerminateProcess (HANDLE process, unsigned retcode); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter); void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc); long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc); long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]); intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]); intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type); intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0, unsigned params = 0, const ULONG_PTR info[] = NULL); void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?", bool readSource = true); const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true, CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread()); int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL, HANDLE thread = GetCurrentThread()); const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false); const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2); bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL, Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL, const char** source = NULL, int context = 2); intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN); bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL); uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL, int useHotPatching = false, HMODULE module = NULL, bool debug = false); bool _txInDll() tx_nodiscard; PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard; bool _txKillProcess (DWORD pid); int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/); bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true); bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid()); IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard; bool _txIsConsoleSubsystem(); const char* _txAppInfo() tx_nodiscard; #if defined (_CLANG_VER) && !defined (_MSC_VER) void _txLibCppDebugFunction (std::__libcpp_debug_info const& info); #endif #endif // TX_COMPILED inline bool _txCanvas_OK () tx_nodiscard; int _txCanvas_SetRefreshLock (int count); const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0, const char msg[] = NULL, ...) tx_printfy (5); bool _txIsBadReadPtr (const void* address); intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3); intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg); bool _txIsTTY (int fd); void txReopenStdio(); #if defined (__CYGWIN__) int _getch(); int _putch (int ch); int _kbhit() tx_nodiscard; #endif //----------------------------------------------------------------------------------------------------------------- // There are macros for __FILE__ and __LINE__ to work properly. #if !defined (NDEBUG) #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \ (assert (cond), true) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Параметр \"%s\" неверен." \ " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка.", #dc), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (TX_ERROR ("\a" "%s" \ "Если вы указали параметр \"%s\", то он неверен.%s", \ (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \ #dc, \ ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка." : "")), 1) ) #else #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #endif //----------------------------------------------------------------------------------------------------------------- // Take action in debug configuration only. // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'( #if !defined (NDEBUG) #define _TX_ON_DEBUG( code ) { code; } #else #define _TX_ON_DEBUG( code ) ; #endif //----------------------------------------------------------------------------------------------------------------- // Invokes an error without location information. "$$" restores TX-related call location context #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__) //----------------------------------------------------------------------------------------------------------------- // Safe call of a function via its pointer #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 ) #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 ) //----------------------------------------------------------------------------------------------------------------- // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x. #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \ !(cond) && GetTickCount() < _t; \ Sleep (_txWindowUpdateInterval)) \ ; \ \ if (!(cond)) \ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); } //----------------------------------------------------------------------------------------------------------------- // Detouring in case of SEH mechanism #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 ) #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; } //----------------------------------------------------------------------------------------------------------------- // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code. #if defined (IN) // #undef IN #endif #if defined (OUT) // #undef OUT #endif //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal global data //! @name Внутренние глобальные данные // // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :) // // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же. // Здесь это сделано только в образовательных целях. // // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс. //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<< const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна _TX_IDM_CONSOLE = 40001, _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas //----------------------------------------------------------------------------------------------------------------- volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize(); volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main() volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT() RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0] HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP), // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock() UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question. int _txConsole = false; // Only first TXLib module in app can own the console bool _txMain = false; // First TXLib wnd opened (closing it terminates program) bool _txIsDll = false; // TXLib module is in DLL volatile bool _txRunning = false; // main() is still running volatile bool _txExit = false; // exit() is active volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE() volatile unsigned _txMouseButtons = 0; volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook(). _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro volatile int _txErrors = 0; // TX_ERROR calls sequental number volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError() volatile long _txSENumber = 0; // SEH exceptions sequental number volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess, (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA, (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp, (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier, (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler, (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace, (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize, (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions, (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64, (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr, (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup, (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64, (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64, (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64, (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext }; volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- extern volatile unsigned _txCanaryFirst; extern volatile unsigned _txCanaryLast; extern volatile HWND _txCanvas_Window; extern volatile unsigned _txCanvas_ThreadId; extern HDC _txCanvas_BackBuf[2]; extern RGBQUAD* _txCanvas_Pixels; extern volatile int _txCanvas_RefreshLock; extern volatile WNDPROC _txAltWndProc; extern volatile bool _txExit; extern volatile int _txOGLError; //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib engine init/check/cleanup //! @name Инициализация/проверка/завершение TXLib //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Early initialization //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize() { if (_txInitialized) return 1; _txInitialized = 1; #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585 #endif #if defined (_TX_ALLOW_TRACE) _txLocLvlSet (1); #endif _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" " "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n"); OutputDebugString ("\n")); _txMainThreadId = GetCurrentThreadId(); _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId); $3 _txIsDll = _txInDll(); $ if (!_txIsDll) { $ _txConsole = ! FindAtom ("_txConsole"); $ (void) AddAtom ("_txConsole"); //-V530 } $ if (_txConsole) { $ _txCheckSourceCP (_TX_CODEPAGE, true); $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ _txOnSignal(); $ if (!*_txLogName) {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); } $ if (!_txIsDll) { $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler)); $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter); } $ ::std::set_terminate (_txOnTerminate); $ ::std::set_new_handler (_txOnNewHandlerAnsi); $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected)); #if defined (_CLANG_VER) && !defined (_MSC_VER) $ ::std::__libcpp_debug_function = _txLibCppDebugFunction; #endif $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true); $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #if defined (_MSC_VER) $ _set_printf_count_output (1); $ _set_new_handler (_txOnNewHandler); $ _set_new_mode (1); #if !defined (_CLANG_VER) $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); $ _CrtSetAllocHook (_txOnAllocHook); $ unsigned mode = _CRTDBG_MODE_FILE; $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0; $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode); $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG); $ _set_abort_behavior (0, _CALL_REPORTFAULT); $ _RTC_SetErrorFunc (_txOnRTCFailure); $ _set_purecall_handler (_txOnPureCall); $ _set_invalid_parameter_handler (_txOnInvalidParam); #endif #if defined (__STDC_LIB_EXT1__) $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi); #endif #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386) $ __setusermatherr (_txOnMatherr); #endif #if !defined (__CYGWIN__) $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR); #endif $ HWND console = _txConsole_Attach(); $ SetWindowTextA (console, txGetModuleFileName (false)); } $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL"); $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL"); $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit); $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit); $ InitializeCriticalSection (&_txCanvas_LockBackBuf); $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted; $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted; $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted; $ Win32::DeleteDC (dc) asserted; $ atexit (_txCleanup); $ if (_txConsole) { $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ tx_fpreset(); $ srand ((unsigned) time (NULL)); //-V202 $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif } $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used" $ return 1; } //----------------------------------------------------------------------------------------------------------------- bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/) { $3 const char* sCodePage = NULL; $ int codePage = 0; $ switch (((unsigned const char*) "А") [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
6932  // деле это сделано вручную через #undef. Чтобы подчеркнуть их локальную природу, у них имена заканчиваются на _.
6933  // Такие дефайны потом не перекосячат весь код после того как, фактически, стали уже не нужны.
6934  //-------------------------------------------------------------------------------------------------------------
6935 
6936  #undef ID_TEXT_
6937  #undef ID_INPUT_
6938 
6939  //-------------------------------------------------------------------------------------------------------------
6940  // Это статический объект, потому что строка в нем должна жить после завершения функции.
6941  //-------------------------------------------------------------------------------------------------------------
6942 
6943  static inputDlg dlg;
6944 
6945  //-------------------------------------------------------------------------------------------------------------
6946  // Передаем layout и запускаем окно диалога //------------------------------------------------------------------------------------------------------------- dlg.dialogBox (layout); //------------------------------------------------------------------------------------------------------------- // Возвращаем адрес строки из статического объекта. Так можно делать, потому что статический объект не умрет // при выходе из функции и строка в нем, соответственно, тоже. Адрес нестатических переменных передавать // синтаксически можно, но ведет к серьезным ошибкам. //------------------------------------------------------------------------------------------------------------- return dlg.str; } #endif // TX_COMPILED //! @} //} //================================================================================================================= //} //================================================================================================================= //================================================================================================================= //{ TXLIB IMPLEMENTATION // Реализация функций библиотеки //================================================================================================================= //! @cond INTERNAL { //----------------------------------------------------------------------------------------------------------------- //{ The Includes //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< _TX_END_NAMESPACE //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch #pragma warning (disable: 4005) // 'name': macro redefinition #endif #if defined (__STRICT_ANSI__) && defined (__STRICT_ANSI__UNDEFINED) #undef __STRICT_ANSI__ #endif //----------------------------------------------------------------------------------------------------------------- #include <stdarg.h> #include <io.h> #include <fcntl.h> #include <process.h> #include <signal.h> #include <setjmp.h> #include <locale.h> #include <limits.h> #include <stdint.h> #include <map> #include <numeric> #include <exception> #include <stdexcept> #include <tlhelp32.h> #include <shellapi.h> #if defined (_GCC_VER) #include <shlobj.h> #include <cxxabi.h> #include <unwind.h> #endif #if defined (__CYGWIN__) #include <stdarg.h> #include <unistd.h> #include <termios.h> #endif #if defined (_MSC_VER) #include <new.h> #include <shlobj.h> #include <ntstatus.h> #include <crtdbg.h> #include <rtcapi.h> #include <dbghelp.h> #endif #if defined (_GCC_VER) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 #include <inttypes.h> #endif //----------------------------------------------------------------------------------------------------------------- #if defined (TX_USE_SPEAK) //-------------------------------------------------------------------------------------- #include <SAPI.h> // <== ЕСЛИ ЗДЕСЬ ОШИБКА, ТО У ВАС НЕТ ФАЙЛА SAPI.h. No SAPI.h file, TXLib isn't guilty :( #endif //-------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (pop) // MSVC: Restore max level #endif #if defined (__STRICT_ANSI__UNDEFINED) #define __STRICT_ANSI__ // Redefine back #endif //----------------------------------------------------------------------------------------------------------------- _TX_BEGIN_NAMESPACE #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //================================================================================================================= //{ DLL functions import, missing types definitions //! @name Импорт внешних библиотек, определение недостающих типов //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Some of structs, consts and interfaces aren't defined in MinGW some early headers. // Copied from Windows SDK 7.0a. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { #ifndef AC_SRC_ALPHA #define AC_SRC_ALPHA 0x01 #endif #ifndef SMTO_ERRORONEXIT #define SMTO_ERRORONEXIT 0x0020 #endif #ifndef NT_CONSOLE_PROPS_SIG #define NT_CONSOLE_PROPS_SIG 0xA0000002 #endif #ifndef NIIF_INFO #define NIIF_INFO 0x00000001 #define NIIF_WARNING 0x00000002 #define NIIF_ERROR 0x00000003 #endif #ifndef NIF_INFO #define NIF_STATE 0x00000008 #define NIF_INFO 0x00000010 #endif #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004 #endif #ifndef SYMOPT_CASE_INSENSITIVE #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_NO_PROMPTS 0x00080000 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 #define SYMOPT_FAVOR_COMPRESSED 0x00800000 #define SYMOPT_FLAT_DIRECTORY 0x00400000 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 #define SYMOPT_OVERWRITE 0x00100000 #define SYMOPT_DEBUG 0x80000000 #endif // SEH exception codes. For GCC, see http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 64-66. #ifndef STATUS_POSSIBLE_DEADLOCK #define STATUS_POSSIBLE_DEADLOCK 0xC0000194 #endif #ifndef STATUS_FLOAT_MULTIPLE_FAULTS #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4 #endif #ifndef STATUS_STACK_BUFFER_OVERRUN #define STATUS_STACK_BUFFER_OVERRUN 0xC0000409 #endif #ifndef STATUS_ASSERTION_FAILURE #define STATUS_ASSERTION_FAILURE 0xC0000420 #endif #ifndef STATUS_WX86_BREAKPOINT #define STATUS_WX86_BREAKPOINT 0x4000001F #endif #ifndef DBG_PRINTEXCEPTION_C #define DBG_PRINTEXCEPTION_C 0x40010006 // OutputDebugStringA() call #endif #ifndef DBG_PRINTEXCEPTION_WIDE_C #define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A // OutputDebugStringW() call #endif #ifndef DBG_THREAD_NAME #define DBG_THREAD_NAME 0x406D1388 #endif #define EXCEPTION_CPP_MSC 0xE06D7363 // '?msc' #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 0x19930520 // '?msc' version magic, see ehdata.h #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 0x19930521 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 0x19930522 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1 0x01994000 // '?msc' version magic #define EXCEPTION_CPP_GCC 0x20474343 // ' GCC' #define EXCEPTION_CPP_GCC_UNWIND 0x21474343 // '!GCC' #define EXCEPTION_CPP_GCC_FORCED 0x22474343 // '"GCC' #define EXCEPTION_CLR_FAILURE 0xE0434f4D // 'аCOM' #define EXCEPTION_CPP_BORLAND_BUILDER 0x0EEDFAE6 // Should never occur here #define EXCEPTION_CPP_BORLAND_DELPHI 0x0EEDFADE // Should never occur here #pragma pack (push, 1) struct CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; }; struct CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; }; struct CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; }; struct DATABLOCK_HEADER { DWORD cbSize; DWORD dwSignature; }; struct NT_CONSOLE_PROPS { DATABLOCK_HEADER dbh; WORD wFillAttribute; WORD wPopupFillAttribute; COORD dwScreenBufferSize; COORD dwWindowSize; COORD dwWindowOrigin; DWORD nFont; DWORD nInputBufferSize; COORD dwFontSize; UINT uFontFamily; UINT uFontWeight; WCHAR FaceName[LF_FACESIZE]; UINT uCursorSize; BOOL bFullScreen; BOOL bQuickEdit; BOOL bInsertMode; BOOL bAutoPosition; UINT uHistoryBufferSize; UINT uNumberOfHistoryBuffers; BOOL bHistoryNoDup; COLORREF ColorTable[16]; }; struct FLASHWINFO { UINT cbSize; HWND hwnd; DWORD dwFlags; UINT uCount; DWORD dwTimeout; }; enum TBPFLAG { TBPF_NOPROGRESS = 0x0, TBPF_INDETERMINATE = 0x1, TBPF_NORMAL = 0x2, TBPF_ERROR = 0x4, TBPF_PAUSED = 0x8 }; #pragma pack (pop) const GUID IID_IShellLink = {0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_IShellLinkDataList = {0x45e2b4ae, 0xb1c3, 0x11d0, {0xb9,0x2f,0x00,0xa0,0xc9,0x03,0x12,0xe1}}; const GUID IID_IPersistFile = {0x0000010b, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; const GUID CLSID_TaskbarList = {0x56fdf344, 0xfd6d, 0x11d0, {0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}}; const GUID CLSID_SpVoice = {0x96749377, 0x3391, 0x11d2, {0x9e,0xe3,0x00,0xc0,0x4f,0x79,0x73,0x96}}; const GUID IID_ISpVoice = {0x6c44df74, 0x72b9, 0x4992, {0xa1,0xec,0xef,0x99,0x6e,0x04,0x22,0xd4}}; typedef DWORD NTSTATUS; typedef ULONG_PTR KAFFINITY; typedef LONG KPRIORITY; struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; wchar_t* Buffer; }; struct RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; UNICODE_STRING DosPath; }; struct CURDIR { UNICODE_STRING DosPath; void* Handle; }; struct RTL_USER_PROCESS_PARAMETERS { ULONG AllocationSize; ULONG Size; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; CURDIR CurrentDirectory; UNICODE_STRING DllPath; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; wchar_t* Environment; ULONG dwX; ULONG dwY; ULONG dwXSize; ULONG dwYSize; ULONG dwXCountChars; ULONG dwYCountChars; ULONG dwFillAttribute; ULONG dwFlags; ULONG wShowWindow; UNICODE_STRING WindowTitle; UNICODE_STRING Desktop; UNICODE_STRING ShellInfo; UNICODE_STRING RuntimeInfo; RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; }; struct PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; void* Reserved3[2]; void* Ldr; RTL_USER_PROCESS_PARAMETERS* ProcessParameters; void* Reserved4[3]; void* AtlThunkSListPtr; void* Reserved5; ULONG Reserved6; void* Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; void* Reserved9[45]; BYTE Reserved10[96]; void* PostProcessInitRoutine; BYTE Reserved11[128]; void* Reserved12[1]; ULONG SessionId; }; struct TEB { void* Reserved1[12]; PEB* ProcessEnvironmentBlock; void* Reserved2[399]; BYTE Reserved3[1952]; void* TlsSlots[64]; BYTE Reserved4[8]; void* Reserved5[26]; void* ReservedForOle; void* Reserved6[4]; void* TlsExpansionSlots; }; struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PEB* PebBaseAddress; KAFFINITY AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; }; enum ADDRESS_MODE { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat }; struct ADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; }; struct KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64 Reserved[5]; }; struct STACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; void* FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; }; struct WOW64_FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE RegisterArea[80]; DWORD Cr0NpxState; }; #pragma pack (push, 4) struct WOW64_CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; WOW64_FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[512]; }; #pragma pack (pop) struct SYMBOL_INFO { ULONG SizeOfStruct; ULONG TypeIndex; ULONG64 Reserved[2]; ULONG info; ULONG Size; ULONG64 ModBase; ULONG Flags; ULONG64 Value; ULONG64 Address; ULONG Register; ULONG Scope; ULONG Tag; ULONG NameLen; ULONG MaxNameLen; char Name[1]; }; struct IMAGEHLP_LINE64 { DWORD SizeOfStruct; void* Key; DWORD LineNumber; char* FileName; DWORD64 Address; }; typedef bool (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64) (HANDLE process, DWORD64 baseAddress, void* buffer, DWORD size, DWORD* bytesRead); typedef void* (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64) (HANDLE process, DWORD64 baseAddress); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64) (HANDLE process, DWORD64 address); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64) (HANDLE process, HANDLE thread, ADDRESS64* address); typedef void (*unexpected_handler)(); #pragma pack (push, 4) struct MINIDUMP_THREAD_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; }; struct MINIDUMP_THREAD_EX_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; ULONG64 BackingStoreBase; ULONG64 BackingStoreEnd; }; struct MINIDUMP_MODULE_CALLBACK { wchar_t* FullPath; ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; VS_FIXEDFILEINFO VersionInfo; void* CvRecord; ULONG SizeOfCvRecord; void* MiscRecord; ULONG SizeOfMiscRecord; }; struct MINIDUMP_INCLUDE_THREAD_CALLBACK { ULONG ThreadId; }; struct MINIDUMP_INCLUDE_MODULE_CALLBACK { ULONG64 BaseOfImage; }; struct MINIDUMP_MEMORY_INFO { ULONG64 BaseAddress; ULONG64 AllocationBase; ULONG32 AllocationProtect; ULONG32 __alignment1; ULONG64 RegionSize; ULONG32 State; ULONG32 Protect; ULONG32 Type; ULONG32 __alignment2; }; struct MINIDUMP_USER_STREAM { ULONG32 Type; ULONG BufferSize; void* Buffer; }; struct MINIDUMP_USER_STREAM_INFORMATION { ULONG UserStreamCount; MINIDUMP_USER_STREAM* UserStreamArray; }; struct MINIDUMP_CALLBACK_INPUT { ULONG ProcessId; HANDLE ProcessHandle; ULONG CallbackType; union //-V2514 { MINIDUMP_THREAD_CALLBACK Thread; MINIDUMP_THREAD_EX_CALLBACK ThreadEx; MINIDUMP_MODULE_CALLBACK Module; MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; }; }; struct MINIDUMP_CALLBACK_OUTPUT { union //-V2514 { ULONG ModuleWriteFlags; ULONG ThreadWriteFlags; ULONG SecondaryFlags; struct { ULONG64 MemoryBase; ULONG MemorySize; }; struct { unsigned CheckCancel; unsigned Cancel; }; HANDLE Handle; //-V117 }; struct { MINIDUMP_MEMORY_INFO VmRegion; unsigned Continue; }; HRESULT Status; }; struct MINIDUMP_EXCEPTION_INFORMATION { DWORD ThreadId; EXCEPTION_POINTERS* ExceptionPointers; unsigned ClientPointers; }; typedef int (WINAPI* MINIDUMP_CALLBACK_ROUTINE) (void* param, MINIDUMP_CALLBACK_INPUT* input, MINIDUMP_CALLBACK_OUTPUT* output); struct MINIDUMP_CALLBACK_INFORMATION { MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; void* CallbackParam; }; enum MINIDUMP_TYPE { MiniDumpNormal = 0x00000000, MiniDumpWithDataSegs = 0x00000001, MiniDumpWithFullMemory = 0x00000002, MiniDumpWithHandleData = 0x00000004, MiniDumpFilterMemory = 0x00000008, MiniDumpScanMemory = 0x00000010, MiniDumpWithUnloadedModules = 0x00000020, MiniDumpWithIndirectlyReferencedMemory = 0x00000040, MiniDumpFilterModulePaths = 0x00000080, MiniDumpWithProcessThreadData = 0x00000100, MiniDumpWithPrivateReadWriteMemory = 0x00000200, MiniDumpWithoutOptionalData = 0x00000400, MiniDumpWithFullMemoryInfo = 0x00000800, MiniDumpWithThreadInfo = 0x00001000, MiniDumpWithCodeSegs = 0x00002000, MiniDumpWithoutAuxiliaryState = 0x00004000, MiniDumpWithFullAuxiliaryState = 0x00008000, MiniDumpWithPrivateWriteCopyMemory = 0x00010000, MiniDumpIgnoreInaccessibleMemory = 0x00020000, MiniDumpWithTokenInformation = 0x00040000 }; #ifndef CONTEXT_ALL #define CONTEXT_ALL ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS ) #endif #pragma pack (pop) } // namespace Win32 #endif // TX_COMPILED #define FOREGROUND_BLACK ( 0 ) #define FOREGROUND_CYAN ( FOREGROUND_BLUE | FOREGROUND_GREEN ) #define FOREGROUND_MAGENTA ( FOREGROUND_BLUE | FOREGROUND_RED ) #define FOREGROUND_DARKYELLOW ( FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_LIGHTGRAY ( FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_DARKGRAY ( FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTBLUE ( FOREGROUND_BLUE | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTGREEN ( FOREGROUND_GREEN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTCYAN ( FOREGROUND_CYAN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTRED ( FOREGROUND_RED | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTMAGENTA ( FOREGROUND_MAGENTA | FOREGROUND_INTENSITY ) #define FOREGROUND_YELLOW ( FOREGROUND_DARKYELLOW | FOREGROUND_INTENSITY ) #define FOREGROUND_WHITE ( FOREGROUND_LIGHTGRAY | FOREGROUND_INTENSITY ) #define BACKGROUND_BLACK ( 0 ) #define BACKGROUND_CYAN ( BACKGROUND_BLUE | BACKGROUND_GREEN ) #define BACKGROUND_MAGENTA ( BACKGROUND_BLUE | BACKGROUND_RED ) #define BACKGROUND_DARKYELLOW ( BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_GRAY ( BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_DARKGRAY ( BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTBLUE ( BACKGROUND_BLUE | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTGREEN ( BACKGROUND_GREEN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTCYAN ( BACKGROUND_CYAN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTRED ( BACKGROUND_RED | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTMAGENTA ( BACKGROUND_MAGENTA | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTYELLOW ( BACKGROUND_DARKYELLOW | BACKGROUND_INTENSITY ) #define BACKGROUND_WHITE ( BACKGROUND_DARKGRAY | BACKGROUND_INTENSITY ) //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ There are copies of MSVC compiler built-in predefined definitions, which are wrong in 64-bit mode. // So we have to override them. See: http://stackoverflow.com/questions/39113168 //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< #if defined (_MSC_VER) // MS ABI C++ Exception Layout namespace Win32 { // --------------------------- // #pragma pack (push, 4) // EXCEPTION_RECORD: // +==================================================+ struct ThrowInfo // |... | { // |NumberParameters: 3, 4 or more | __int32 attributes; // |ExceptionInformation[0]: MS signature 0x19930520 | __int32 pmfnUnwind; // |ExceptionInformation[1]: object* thrown | __int32 pForwardCompat; // |ExceptionInformation[2]: ThrowInfo* --------------+---+ __int32 pCatchableTypeArray; // |ExceptionInformation[3]: ImageBase (if params > 3)| | }; // +==================================================+ | // | struct CatchableTypeArray // ThrowInfo: | { // +======================================+ <-------+ __int32 nCatchableTypes; // | ... | __int32 arrayOfCatchableTypes[]; // +-----+-- pCatchableTypeArray (ptr/RVA) | }; // | +======================================+ // | struct CatchableType // | CatchableTypeArray: { // +---> +======================================+ __int32 properties; // | ... | __int32 pType; // +-----+-- arrayOfCatchableTypes[0] (ptr/RVA) | __int32 thisDisplacement[3]; // struct _PMD // | +======================================+ __int32 sizeOrOffset; // | __int32 copyFunction; // | CatchableType: }; // +---> +====================+ // | ... | std::type_info: #pragma pack (pop) // | pType (ptr/RVA) ---+------> +==================+ // | ... | |type_info data | } // namespace Win32 // +====================+ |... | // +==================+ #endif // Similar to __CxxDetectRethrow(), see C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\crtsrc\vcruntime\frame.cpp: #define _TX_MSC__CXX_DETECT_RETHROW( exc ) \ ( \ (exc) && \ (exc) -> ExceptionCode == EXCEPTION_CPP_MSC && \ (exc) -> NumberParameters >= 3 && \ \ ((exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3) && \ \ (exc) -> ExceptionInformation[2] == 0 \ ) #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ The corresponding structures for GCC // // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h // See: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi //----------------------------------------------------------------------------------------------------------------- #if defined (_GCC_VER) #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // GCC ABI C++ Exception layout. A/B are ExceptionInformation[0]. namespace ABI { // -------------------------------------------------------------- // struct __cxa_exception // Case A: "_Unwind_Exception* A" is undependent exception: { // -------------------------------------------------------- union { // struct // __cxa_exception: std::type_info: { // -*--+====================+ +==================+ ::std::type_info* exceptionType; // ^ |exceptionType* -----+---->|type_info data | void (*exceptionDestructor)(void*); // | |... | |... | }; // -1 | | +==================+ struct // | | | { // A >----|--+--------------------+ __cxa_exception* primaryException; // | | |unwindHeader | void (*padding)(); // +1 | | | }; // | | | | }; // V | | | // -*--- +====================+ void (*unexpected_handler)(); // |object | std::terminate_handler terminateHandler; // +--------------------+ // __cxa_exception* nextException; // Case B: "_Unwind_Exception* B" is dependent exception int handlerCount; // (unwindHeader.exception_class & 1 != 0): int handlerSwitchValue; // ----------------------------------------------------- const unsigned char* actionRecord; // const unsigned char* languageSpecificData; // __cxa_exception: __cxa_exception: void* catchTemp; // -*--+====================+ -*--+=================+ void* adjustedPtr; // ^ |primaryException* --+-- ^ |exceptionType* | // | |... | \ | |... | _Unwind_Exception unwindHeader; // -1 | | | | | | }; // | | | | | | | // B >----|--+--------------------+ | -1 +-----------------+ struct __cxa_eh_globals // | | |unwindHeader | | | |unwindHeader | { // +1 | | | | | | | __cxa_exception* caughtExceptions; // | | | | | | | | unsigned int uncaughtExceptions; // V | | | \ | | | }; // -*--- +====================+ -->*--+=================+ // |... | |object | } // namespace ABI // . . | | // +-----------------+ extern "C" ABI::__cxa_eh_globals* __cxa_get_globals(); #endif // TX_COMPILED #endif //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Hand-made IAT. // Some IDEs don't link with these libs by default in console projects, so do sunrise by hand. :( //----------------------------------------------------------------------------------------------------------------- // Hand-made DLLIMPORT helpers #define _TX_DLLIMPORT( lib, retval, name, params ) TX_DLLIMPORT (true, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_OPT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_CRT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, please) void (*_txDllImport (const char dllFileName[], const char funcName[], bool required = true)) (); //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { _TX_DLLIMPORT ("GDI32", HDC, CreateCompatibleDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateCompatibleBitmap, (HDC dc, int width, int height)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetStockObject, (int object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, SelectObject, (HDC dc, HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetCurrentObject, (HDC dc, unsigned objectType)); _TX_DLLIMPORT ("GDI32", int, GetObjectA, (HGDIOBJ obj, int bufsize, void* buffer)); _TX_DLLIMPORT ("GDI32", DWORD, GetObjectType, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", bool, DeleteDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", bool, DeleteObject, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", COLORREF, SetTextColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, SetBkColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", int, SetBkMode, (HDC dc, int bkMode)); _TX_DLLIMPORT ("GDI32", HFONT, CreateFontA, (int height, int width, int escapement, int orientation, int weight, DWORD italic, DWORD underline, DWORD strikeout, DWORD charSet, DWORD outputPrec, DWORD clipPrec, DWORD quality, DWORD pitchAndFamily, const char face[])); _TX_DLLIMPORT ("GDI32", int, EnumFontFamiliesExA, (HDC dc, LPLOGFONT logFont, FONTENUMPROC enumProc, LPARAM lParam, DWORD reserved)); _TX_DLLIMPORT ("GDI32", COLORREF, SetPixel, (HDC dc, int x, int y, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, GetPixel, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", HPEN, CreatePen, (int penStyle, int width, COLORREF color)); _TX_DLLIMPORT ("GDI32", HBRUSH, CreateSolidBrush, (COLORREF color)); _TX_DLLIMPORT ("GDI32", bool, MoveToEx, (HDC dc, int x, int y, POINT* point)); _TX_DLLIMPORT ("GDI32", bool, LineTo, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", bool, Polygon, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Polyline, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, PolyBezier, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Rectangle, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, RoundRect, (HDC dc, int x0, int y0, int x1, int y1, int sizeX, int sizeY)); _TX_DLLIMPORT ("GDI32", bool, Ellipse, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, Arc, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Pie, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Chord, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, TextOutA, (HDC dc, int x, int y, const char string[], int length)); _TX_DLLIMPORT ("GDI32", UINT, SetTextAlign, (HDC dc, unsigned mode)); _TX_DLLIMPORT ("GDI32", bool, GetTextExtentPoint32A, (HDC dc, const char string[], int length, SIZE* size)); _TX_DLLIMPORT ("GDI32", bool, ExtFloodFill, (HDC dc, int x, int y, COLORREF color, unsigned type)); _TX_DLLIMPORT ("GDI32", bool, BitBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, StretchBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, PlgBlt, (HDC dest, const POINT* parallelogram, HDC src, int xSrc, int ySrc, int width, int height, HBITMAP mask, int xMask, int yMask)); _TX_DLLIMPORT ("GDI32", int, SetDIBitsToDevice, (HDC dc, int xDest, int yDest, DWORD width, DWORD height, int xSrc, int ySrc, unsigned startLine, unsigned numLines, const void* data, const BITMAPINFO* info, unsigned colorUse)); _TX_DLLIMPORT ("GDI32", int, GetDIBits, (HDC hdc, HBITMAP hbmp, unsigned uStartScan, unsigned cScanLines, void* lpvBits, BITMAPINFO* lpbi, unsigned usage)); _TX_DLLIMPORT ("GDI32", bool, PatBlt, (HDC dc, int x0, int y0, int width, int height, DWORD rOp)); _TX_DLLIMPORT ("GDI32", int, SetROP2, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", int, SetStretchBltMode, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", DWORD, GdiSetBatchLimit, (DWORD limit)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateDIBSection, (HDC dc, const BITMAPINFO* bmInfo, unsigned colorUsage, void **vBits, HANDLE section, DWORD offset)); _TX_DLLIMPORT ("User32", int, DrawTextA, (HDC dc, const char text[], int length, RECT* rect, unsigned format)); _TX_DLLIMPORT ("User32", HANDLE, LoadImageA, (HINSTANCE inst, const char name[], unsigned type, int sizex, int sizey, unsigned mode)); _TX_DLLIMPORT_OPT ("User32", bool, IsHungAppWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", HWND, GhostWindowFromHungWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", bool, FlashWindowEx, (const FLASHWINFO* flash)); _TX_DLLIMPORT ("WinMM", bool, PlaySound, (const char sound[], HMODULE mod, DWORD mode)); _TX_DLLIMPORT_OPT ("MSImg32", bool, TransparentBlt, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, unsigned transparentColor)); _TX_DLLIMPORT_OPT ("MSImg32", bool, AlphaBlend, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, BLENDFUNCTION blending)); _TX_DLLIMPORT ("Kernel32", void, ExitProcess, (unsigned retcode)); _TX_DLLIMPORT ("Kernel32", bool, TerminateProcess, (HANDLE process, unsigned retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalExit, (int retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalAppExitA, (unsigned action, const char message[])); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetThreadId, (HANDLE thread)); _TX_DLLIMPORT ("Kernel32", HWND, GetConsoleWindow, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetConsoleFont, (HANDLE con, DWORD fontIndex)); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetNumberOfConsoleFonts, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFont, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFO* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", void, RtlCaptureContext, (CONTEXT* contextRecord)); _TX_DLLIMPORT_OPT ("Kernel32", USHORT, RtlCaptureStackBackTrace, (DWORD framesToSkip, DWORD framesToCapture, void** backTrace, DWORD* hash)); _TX_DLLIMPORT_OPT ("Kernel32", void*, AddVectoredExceptionHandler, (unsigned long firstHandler, PVECTORED_EXCEPTION_HANDLER handler)); _TX_DLLIMPORT_OPT ("Kernel32", unsigned, RemoveVectoredExceptionHandler,(void* handler)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetModuleHandleEx, (DWORD flags, const char moduleName[], HMODULE* module)); _TX_DLLIMPORT_OPT ("Kernel32", bool, IsWow64Process, (HANDLE process, int* isWow64Process)); _TX_DLLIMPORT_OPT ("Kernel32", bool, Wow64GetThreadContext, (HANDLE thread, WOW64_CONTEXT* context)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetThreadStackGuarantee, (unsigned long* stackSize)); _TX_DLLIMPORT ("OLE32", HRESULT, CoInitialize, (void*)); _TX_DLLIMPORT ("OLE32", HRESULT, CoCreateInstance, (REFCLSID clsId, IUnknown*, DWORD, REFIID iId, void** value)); _TX_DLLIMPORT ("OLE32", void, CoUninitialize, (void)); _TX_DLLIMPORT ("Shell32", HINSTANCE,ShellExecuteA, (HWND wnd, const char operation[], const char file[], const char parameters[], const char directory[], int showCmd)); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIA, (const char string[], const char search[])); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIW, (const wchar_t string[], const wchar_t search[])); _TX_DLLIMPORT_OPT ("NTDLL", char*, wine_get_version, (void)); _TX_DLLIMPORT ("NTDLL", NTSTATUS, NtQueryInformationProcess, (HANDLE process, int infoClass, void* processInfo, unsigned long szProcessInfo, unsigned long* szReturnInfo)); _TX_DLLIMPORT_CRT ("MSVCRT", void, exit, (int retcode)); _TX_DLLIMPORT_CRT ("MSVCRT", void, _cexit, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _fpreset, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _controlfp, (unsigned control, unsigned mask)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthread, (void (__cdecl* start_address) (void*), unsigned stack_size, void* arglist)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthreadex, (void* security, unsigned stack_size, unsigned (__stdcall* start_address) (void*), void *arglist, unsigned init_flag, unsigned* thread_addr)); _TX_DLLIMPORT_CRT ("MSVCRT", char*, __unDName, (char* outStr, const char* mangledName, int outStrLen, void* (*mallocFunc) (size_t size), void (*freeFunc) (void *pointer), unsigned short flags)); _TX_DLLIMPORT_CRT ("MSVCRT", unexpected_handler, set_unexpected, (unexpected_handler handler)); _TX_DLLIMPORT_OPT ("OpenGL32", HDC, wglGetCurrentDC, (void)); _TX_DLLIMPORT_OPT ("OpenGL32", unsigned, glGetError, (void)); _TX_DLLIMPORT_OPT ("Glu32", const char*, gluErrorString, (unsigned error)); _TX_DLLIMPORT_OPT ("ComDlg32", DWORD, CommDlgExtendedError, (void)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, MiniDumpWriteDump, (HANDLE process, DWORD processId, HANDLE file, MINIDUMP_TYPE dumpType, MINIDUMP_EXCEPTION_INFORMATION* exceptionParam, MINIDUMP_USER_STREAM_INFORMATION* userStreamParam, MINIDUMP_CALLBACK_INFORMATION* callbackParam)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("DbgHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); namespace MinGW { _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("MgwHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); } // namespace MinGW } // namespace Win32 #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal function prototypes, macros and constants // @name Прототипы внутренних функций, макросы и константы //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize(); void _txCleanup(); HWND _txCanvas_CreateWindow (const SIZE* size); bool _txCanvas_OnCREATE (HWND wnd); bool _txCanvas_OnDESTROY (HWND wnd); bool _txCanvas_OnCLOSE (HWND); bool _txCanvas_OnPAINT (HWND wnd); bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down); bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info); bool _txCanvas_OnTIMER (HWND wnd, WPARAM id); bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords); bool _txCanvas_OnMOUSELEAVE (HWND wnd); bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd); bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd); unsigned WINAPI _txCanvas_ThreadProc (void* data); LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard; bool _txBuffer_Delete (HDC* dc); bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC()); HWND _txConsole_Attach(); bool _txConsole_OK() tx_nodiscard; bool _txConsole_Detach (bool activate); bool _txConsole_Draw (HDC dc); bool _txConsole_SetUnicodeFont(); const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra); HWND txCreateExtraWindow (CREATESTRUCT createData); HICON _txCreateTXIcon (int size) tx_nodiscard; int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL, int checkOfs = 0, const wchar_t checkLetters[2] = NULL); int _txPauseBeforeTermination (HWND canvas); int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard; void _txActivateWindow (HWND wnd, unsigned mode); int _txGetInput(); LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); const char* _txPlayVideo_FindVLC() tx_nodiscard; bool _txCreateShortcut (const char shortcutName[], const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL, const char description[] = NULL, int cmdShow = SW_SHOWNORMAL, const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0, COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD)); void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) tx_nodiscard; void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]); const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args); void _txOnTerminate(); void _txOnUnexpected(); void _txOnPureCall(); void _txOnNewHandlerAnsi(); int _txOnNewHandler (size_t size); void _txOnSignal (int signal = 0, int fpe = 0); BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type); void _txOnSecurityError (int code, void*); void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code); int _txOnMatherr (_exception* except); void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned line, uintptr_t); int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line); int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5); int _txOnErrorReport (int type, const char* text, int* ret); int tx_glGetError (int setError = INT_MIN); void _txOnCExit(); void _txOnExit (int retcode); void _txOnFatalExit (int retcode); void _txOnExitProcess (unsigned retcode); void _txOnFatalAppExitA (unsigned action, const char message[]); bool _txOnTerminateProcess (HANDLE process, unsigned retcode); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter); void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc); long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc); long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]); intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]); intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type); intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0, unsigned params = 0, const ULONG_PTR info[] = NULL); void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?", bool readSource = true); const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true, CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread()); int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL, HANDLE thread = GetCurrentThread()); const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false); const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2); bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL, Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL, const char** source = NULL, int context = 2); intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN); bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL); uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL, int useHotPatching = false, HMODULE module = NULL, bool debug = false); bool _txInDll() tx_nodiscard; PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard; bool _txKillProcess (DWORD pid); int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/); bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true); bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid()); IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard; bool _txIsConsoleSubsystem(); const char* _txAppInfo() tx_nodiscard; #if defined (_CLANG_VER) && !defined (_MSC_VER) void _txLibCppDebugFunction (std::__libcpp_debug_info const& info); #endif #endif // TX_COMPILED inline bool _txCanvas_OK () tx_nodiscard; int _txCanvas_SetRefreshLock (int count); const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0, const char msg[] = NULL, ...) tx_printfy (5); bool _txIsBadReadPtr (const void* address); intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3); intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg); bool _txIsTTY (int fd); void txReopenStdio(); #if defined (__CYGWIN__) int _getch(); int _putch (int ch); int _kbhit() tx_nodiscard; #endif //----------------------------------------------------------------------------------------------------------------- // There are macros for __FILE__ and __LINE__ to work properly. #if !defined (NDEBUG) #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \ (assert (cond), true) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Параметр \"%s\" неверен." \ " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка.", #dc), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (TX_ERROR ("\a" "%s" \ "Если вы указали параметр \"%s\", то он неверен.%s", \ (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \ #dc, \ ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка." : "")), 1) ) #else #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #endif //----------------------------------------------------------------------------------------------------------------- // Take action in debug configuration only. // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'( #if !defined (NDEBUG) #define _TX_ON_DEBUG( code ) { code; } #else #define _TX_ON_DEBUG( code ) ; #endif //----------------------------------------------------------------------------------------------------------------- // Invokes an error without location information. "$$" restores TX-related call location context #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__) //----------------------------------------------------------------------------------------------------------------- // Safe call of a function via its pointer #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 ) #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 ) //----------------------------------------------------------------------------------------------------------------- // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x. #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \ !(cond) && GetTickCount() < _t; \ Sleep (_txWindowUpdateInterval)) \ ; \ \ if (!(cond)) \ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); } //----------------------------------------------------------------------------------------------------------------- // Detouring in case of SEH mechanism #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 ) #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; } //----------------------------------------------------------------------------------------------------------------- // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code. #if defined (IN) // #undef IN #endif #if defined (OUT) // #undef OUT #endif //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal global data //! @name Внутренние глобальные данные // // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :) // // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же. // Здесь это сделано только в образовательных целях. // // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс. //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<< const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна _TX_IDM_CONSOLE = 40001, _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas //----------------------------------------------------------------------------------------------------------------- volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize(); volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main() volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT() RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0] HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP), // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock() UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question. int _txConsole = false; // Only first TXLib module in app can own the console bool _txMain = false; // First TXLib wnd opened (closing it terminates program) bool _txIsDll = false; // TXLib module is in DLL volatile bool _txRunning = false; // main() is still running volatile bool _txExit = false; // exit() is active volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE() volatile unsigned _txMouseButtons = 0; volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook(). _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro volatile int _txErrors = 0; // TX_ERROR calls sequental number volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError() volatile long _txSENumber = 0; // SEH exceptions sequental number volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess, (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA, (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp, (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier, (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler, (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace, (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize, (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions, (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64, (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr, (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup, (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64, (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64, (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64, (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext }; volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- extern volatile unsigned _txCanaryFirst; extern volatile unsigned _txCanaryLast; extern volatile HWND _txCanvas_Window; extern volatile unsigned _txCanvas_ThreadId; extern HDC _txCanvas_BackBuf[2]; extern RGBQUAD* _txCanvas_Pixels; extern volatile int _txCanvas_RefreshLock; extern volatile WNDPROC _txAltWndProc; extern volatile bool _txExit; extern volatile int _txOGLError; //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib engine init/check/cleanup //! @name Инициализация/проверка/завершение TXLib //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Early initialization //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize() { if (_txInitialized) return 1; _txInitialized = 1; #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585 #endif #if defined (_TX_ALLOW_TRACE) _txLocLvlSet (1); #endif _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" " "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n"); OutputDebugString ("\n")); _txMainThreadId = GetCurrentThreadId(); _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId); $3 _txIsDll = _txInDll(); $ if (!_txIsDll) { $ _txConsole = ! FindAtom ("_txConsole"); $ (void) AddAtom ("_txConsole"); //-V530 } $ if (_txConsole) { $ _txCheckSourceCP (_TX_CODEPAGE, true); $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ _txOnSignal(); $ if (!*_txLogName) {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); } $ if (!_txIsDll) { $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler)); $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter); } $ ::std::set_terminate (_txOnTerminate); $ ::std::set_new_handler (_txOnNewHandlerAnsi); $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected)); #if defined (_CLANG_VER) && !defined (_MSC_VER) $ ::std::__libcpp_debug_function = _txLibCppDebugFunction; #endif $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true); $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #if defined (_MSC_VER) $ _set_printf_count_output (1); $ _set_new_handler (_txOnNewHandler); $ _set_new_mode (1); #if !defined (_CLANG_VER) $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); $ _CrtSetAllocHook (_txOnAllocHook); $ unsigned mode = _CRTDBG_MODE_FILE; $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0; $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode); $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG); $ _set_abort_behavior (0, _CALL_REPORTFAULT); $ _RTC_SetErrorFunc (_txOnRTCFailure); $ _set_purecall_handler (_txOnPureCall); $ _set_invalid_parameter_handler (_txOnInvalidParam); #endif #if defined (__STDC_LIB_EXT1__) $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi); #endif #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386) $ __setusermatherr (_txOnMatherr); #endif #if !defined (__CYGWIN__) $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR); #endif $ HWND console = _txConsole_Attach(); $ SetWindowTextA (console, txGetModuleFileName (false)); } $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL"); $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL"); $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit); $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit); $ InitializeCriticalSection (&_txCanvas_LockBackBuf); $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted; $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted; $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted; $ Win32::DeleteDC (dc) asserted; $ atexit (_txCleanup); $ if (_txConsole) { $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ tx_fpreset(); $ srand ((unsigned) time (NULL)); //-V202 $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif } $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used" $ return 1; } //----------------------------------------------------------------------------------------------------------------- bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/) { $3 const char* sCodePage = NULL; $ int codePage = 0; $ switch (((unsigned const char*) "А") [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
6947  //-------------------------------------------------------------------------------------------------------------
6948 
6949  dlg.dialogBox (layout);
6950 
6951  //-------------------------------------------------------------------------------------------------------------
6952  // Возвращаем адрес строки из статического объекта. Так можно делать, потому что статический объект не умрет // при выходе из функции и строка в нем, соответственно, тоже. Адрес нестатических переменных передавать // синтаксически можно, но ведет к серьезным ошибкам. //------------------------------------------------------------------------------------------------------------- return dlg.str; } #endif // TX_COMPILED //! @} //} //================================================================================================================= //} //================================================================================================================= //================================================================================================================= //{ TXLIB IMPLEMENTATION // Реализация функций библиотеки //================================================================================================================= //! @cond INTERNAL { //----------------------------------------------------------------------------------------------------------------- //{ The Includes //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< _TX_END_NAMESPACE //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch #pragma warning (disable: 4005) // 'name': macro redefinition #endif #if defined (__STRICT_ANSI__) && defined (__STRICT_ANSI__UNDEFINED) #undef __STRICT_ANSI__ #endif //----------------------------------------------------------------------------------------------------------------- #include <stdarg.h> #include <io.h> #include <fcntl.h> #include <process.h> #include <signal.h> #include <setjmp.h> #include <locale.h> #include <limits.h> #include <stdint.h> #include <map> #include <numeric> #include <exception> #include <stdexcept> #include <tlhelp32.h> #include <shellapi.h> #if defined (_GCC_VER) #include <shlobj.h> #include <cxxabi.h> #include <unwind.h> #endif #if defined (__CYGWIN__) #include <stdarg.h> #include <unistd.h> #include <termios.h> #endif #if defined (_MSC_VER) #include <new.h> #include <shlobj.h> #include <ntstatus.h> #include <crtdbg.h> #include <rtcapi.h> #include <dbghelp.h> #endif #if defined (_GCC_VER) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 #include <inttypes.h> #endif //----------------------------------------------------------------------------------------------------------------- #if defined (TX_USE_SPEAK) //-------------------------------------------------------------------------------------- #include <SAPI.h> // <== ЕСЛИ ЗДЕСЬ ОШИБКА, ТО У ВАС НЕТ ФАЙЛА SAPI.h. No SAPI.h file, TXLib isn't guilty :( #endif //-------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (pop) // MSVC: Restore max level #endif #if defined (__STRICT_ANSI__UNDEFINED) #define __STRICT_ANSI__ // Redefine back #endif //----------------------------------------------------------------------------------------------------------------- _TX_BEGIN_NAMESPACE #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //================================================================================================================= //{ DLL functions import, missing types definitions //! @name Импорт внешних библиотек, определение недостающих типов //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Some of structs, consts and interfaces aren't defined in MinGW some early headers. // Copied from Windows SDK 7.0a. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { #ifndef AC_SRC_ALPHA #define AC_SRC_ALPHA 0x01 #endif #ifndef SMTO_ERRORONEXIT #define SMTO_ERRORONEXIT 0x0020 #endif #ifndef NT_CONSOLE_PROPS_SIG #define NT_CONSOLE_PROPS_SIG 0xA0000002 #endif #ifndef NIIF_INFO #define NIIF_INFO 0x00000001 #define NIIF_WARNING 0x00000002 #define NIIF_ERROR 0x00000003 #endif #ifndef NIF_INFO #define NIF_STATE 0x00000008 #define NIF_INFO 0x00000010 #endif #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004 #endif #ifndef SYMOPT_CASE_INSENSITIVE #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_NO_PROMPTS 0x00080000 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 #define SYMOPT_FAVOR_COMPRESSED 0x00800000 #define SYMOPT_FLAT_DIRECTORY 0x00400000 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 #define SYMOPT_OVERWRITE 0x00100000 #define SYMOPT_DEBUG 0x80000000 #endif // SEH exception codes. For GCC, see http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 64-66. #ifndef STATUS_POSSIBLE_DEADLOCK #define STATUS_POSSIBLE_DEADLOCK 0xC0000194 #endif #ifndef STATUS_FLOAT_MULTIPLE_FAULTS #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4 #endif #ifndef STATUS_STACK_BUFFER_OVERRUN #define STATUS_STACK_BUFFER_OVERRUN 0xC0000409 #endif #ifndef STATUS_ASSERTION_FAILURE #define STATUS_ASSERTION_FAILURE 0xC0000420 #endif #ifndef STATUS_WX86_BREAKPOINT #define STATUS_WX86_BREAKPOINT 0x4000001F #endif #ifndef DBG_PRINTEXCEPTION_C #define DBG_PRINTEXCEPTION_C 0x40010006 // OutputDebugStringA() call #endif #ifndef DBG_PRINTEXCEPTION_WIDE_C #define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A // OutputDebugStringW() call #endif #ifndef DBG_THREAD_NAME #define DBG_THREAD_NAME 0x406D1388 #endif #define EXCEPTION_CPP_MSC 0xE06D7363 // '?msc' #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 0x19930520 // '?msc' version magic, see ehdata.h #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 0x19930521 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 0x19930522 // '?msc' version magic #define EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1 0x01994000 // '?msc' version magic #define EXCEPTION_CPP_GCC 0x20474343 // ' GCC' #define EXCEPTION_CPP_GCC_UNWIND 0x21474343 // '!GCC' #define EXCEPTION_CPP_GCC_FORCED 0x22474343 // '"GCC' #define EXCEPTION_CLR_FAILURE 0xE0434f4D // 'аCOM' #define EXCEPTION_CPP_BORLAND_BUILDER 0x0EEDFAE6 // Should never occur here #define EXCEPTION_CPP_BORLAND_DELPHI 0x0EEDFADE // Should never occur here #pragma pack (push, 1) struct CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; }; struct CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; }; struct CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; }; struct DATABLOCK_HEADER { DWORD cbSize; DWORD dwSignature; }; struct NT_CONSOLE_PROPS { DATABLOCK_HEADER dbh; WORD wFillAttribute; WORD wPopupFillAttribute; COORD dwScreenBufferSize; COORD dwWindowSize; COORD dwWindowOrigin; DWORD nFont; DWORD nInputBufferSize; COORD dwFontSize; UINT uFontFamily; UINT uFontWeight; WCHAR FaceName[LF_FACESIZE]; UINT uCursorSize; BOOL bFullScreen; BOOL bQuickEdit; BOOL bInsertMode; BOOL bAutoPosition; UINT uHistoryBufferSize; UINT uNumberOfHistoryBuffers; BOOL bHistoryNoDup; COLORREF ColorTable[16]; }; struct FLASHWINFO { UINT cbSize; HWND hwnd; DWORD dwFlags; UINT uCount; DWORD dwTimeout; }; enum TBPFLAG { TBPF_NOPROGRESS = 0x0, TBPF_INDETERMINATE = 0x1, TBPF_NORMAL = 0x2, TBPF_ERROR = 0x4, TBPF_PAUSED = 0x8 }; #pragma pack (pop) const GUID IID_IShellLink = {0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_IShellLinkDataList = {0x45e2b4ae, 0xb1c3, 0x11d0, {0xb9,0x2f,0x00,0xa0,0xc9,0x03,0x12,0xe1}}; const GUID IID_IPersistFile = {0x0000010b, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; const GUID IID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; const GUID CLSID_TaskbarList = {0x56fdf344, 0xfd6d, 0x11d0, {0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}}; const GUID CLSID_SpVoice = {0x96749377, 0x3391, 0x11d2, {0x9e,0xe3,0x00,0xc0,0x4f,0x79,0x73,0x96}}; const GUID IID_ISpVoice = {0x6c44df74, 0x72b9, 0x4992, {0xa1,0xec,0xef,0x99,0x6e,0x04,0x22,0xd4}}; typedef DWORD NTSTATUS; typedef ULONG_PTR KAFFINITY; typedef LONG KPRIORITY; struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; wchar_t* Buffer; }; struct RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; UNICODE_STRING DosPath; }; struct CURDIR { UNICODE_STRING DosPath; void* Handle; }; struct RTL_USER_PROCESS_PARAMETERS { ULONG AllocationSize; ULONG Size; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; CURDIR CurrentDirectory; UNICODE_STRING DllPath; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; wchar_t* Environment; ULONG dwX; ULONG dwY; ULONG dwXSize; ULONG dwYSize; ULONG dwXCountChars; ULONG dwYCountChars; ULONG dwFillAttribute; ULONG dwFlags; ULONG wShowWindow; UNICODE_STRING WindowTitle; UNICODE_STRING Desktop; UNICODE_STRING ShellInfo; UNICODE_STRING RuntimeInfo; RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; }; struct PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; void* Reserved3[2]; void* Ldr; RTL_USER_PROCESS_PARAMETERS* ProcessParameters; void* Reserved4[3]; void* AtlThunkSListPtr; void* Reserved5; ULONG Reserved6; void* Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; void* Reserved9[45]; BYTE Reserved10[96]; void* PostProcessInitRoutine; BYTE Reserved11[128]; void* Reserved12[1]; ULONG SessionId; }; struct TEB { void* Reserved1[12]; PEB* ProcessEnvironmentBlock; void* Reserved2[399]; BYTE Reserved3[1952]; void* TlsSlots[64]; BYTE Reserved4[8]; void* Reserved5[26]; void* ReservedForOle; void* Reserved6[4]; void* TlsExpansionSlots; }; struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PEB* PebBaseAddress; KAFFINITY AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; }; enum ADDRESS_MODE { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat }; struct ADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; }; struct KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64 Reserved[5]; }; struct STACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; void* FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; }; struct WOW64_FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE RegisterArea[80]; DWORD Cr0NpxState; }; #pragma pack (push, 4) struct WOW64_CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; WOW64_FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[512]; }; #pragma pack (pop) struct SYMBOL_INFO { ULONG SizeOfStruct; ULONG TypeIndex; ULONG64 Reserved[2]; ULONG info; ULONG Size; ULONG64 ModBase; ULONG Flags; ULONG64 Value; ULONG64 Address; ULONG Register; ULONG Scope; ULONG Tag; ULONG NameLen; ULONG MaxNameLen; char Name[1]; }; struct IMAGEHLP_LINE64 { DWORD SizeOfStruct; void* Key; DWORD LineNumber; char* FileName; DWORD64 Address; }; typedef bool (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64) (HANDLE process, DWORD64 baseAddress, void* buffer, DWORD size, DWORD* bytesRead); typedef void* (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64) (HANDLE process, DWORD64 baseAddress); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64) (HANDLE process, DWORD64 address); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64) (HANDLE process, HANDLE thread, ADDRESS64* address); typedef void (*unexpected_handler)(); #pragma pack (push, 4) struct MINIDUMP_THREAD_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; }; struct MINIDUMP_THREAD_EX_CALLBACK { ULONG ThreadId; HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; ULONG64 StackBase; ULONG64 StackEnd; ULONG64 BackingStoreBase; ULONG64 BackingStoreEnd; }; struct MINIDUMP_MODULE_CALLBACK { wchar_t* FullPath; ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; VS_FIXEDFILEINFO VersionInfo; void* CvRecord; ULONG SizeOfCvRecord; void* MiscRecord; ULONG SizeOfMiscRecord; }; struct MINIDUMP_INCLUDE_THREAD_CALLBACK { ULONG ThreadId; }; struct MINIDUMP_INCLUDE_MODULE_CALLBACK { ULONG64 BaseOfImage; }; struct MINIDUMP_MEMORY_INFO { ULONG64 BaseAddress; ULONG64 AllocationBase; ULONG32 AllocationProtect; ULONG32 __alignment1; ULONG64 RegionSize; ULONG32 State; ULONG32 Protect; ULONG32 Type; ULONG32 __alignment2; }; struct MINIDUMP_USER_STREAM { ULONG32 Type; ULONG BufferSize; void* Buffer; }; struct MINIDUMP_USER_STREAM_INFORMATION { ULONG UserStreamCount; MINIDUMP_USER_STREAM* UserStreamArray; }; struct MINIDUMP_CALLBACK_INPUT { ULONG ProcessId; HANDLE ProcessHandle; ULONG CallbackType; union //-V2514 { MINIDUMP_THREAD_CALLBACK Thread; MINIDUMP_THREAD_EX_CALLBACK ThreadEx; MINIDUMP_MODULE_CALLBACK Module; MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; }; }; struct MINIDUMP_CALLBACK_OUTPUT { union //-V2514 { ULONG ModuleWriteFlags; ULONG ThreadWriteFlags; ULONG SecondaryFlags; struct { ULONG64 MemoryBase; ULONG MemorySize; }; struct { unsigned CheckCancel; unsigned Cancel; }; HANDLE Handle; //-V117 }; struct { MINIDUMP_MEMORY_INFO VmRegion; unsigned Continue; }; HRESULT Status; }; struct MINIDUMP_EXCEPTION_INFORMATION { DWORD ThreadId; EXCEPTION_POINTERS* ExceptionPointers; unsigned ClientPointers; }; typedef int (WINAPI* MINIDUMP_CALLBACK_ROUTINE) (void* param, MINIDUMP_CALLBACK_INPUT* input, MINIDUMP_CALLBACK_OUTPUT* output); struct MINIDUMP_CALLBACK_INFORMATION { MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; void* CallbackParam; }; enum MINIDUMP_TYPE { MiniDumpNormal = 0x00000000, MiniDumpWithDataSegs = 0x00000001, MiniDumpWithFullMemory = 0x00000002, MiniDumpWithHandleData = 0x00000004, MiniDumpFilterMemory = 0x00000008, MiniDumpScanMemory = 0x00000010, MiniDumpWithUnloadedModules = 0x00000020, MiniDumpWithIndirectlyReferencedMemory = 0x00000040, MiniDumpFilterModulePaths = 0x00000080, MiniDumpWithProcessThreadData = 0x00000100, MiniDumpWithPrivateReadWriteMemory = 0x00000200, MiniDumpWithoutOptionalData = 0x00000400, MiniDumpWithFullMemoryInfo = 0x00000800, MiniDumpWithThreadInfo = 0x00001000, MiniDumpWithCodeSegs = 0x00002000, MiniDumpWithoutAuxiliaryState = 0x00004000, MiniDumpWithFullAuxiliaryState = 0x00008000, MiniDumpWithPrivateWriteCopyMemory = 0x00010000, MiniDumpIgnoreInaccessibleMemory = 0x00020000, MiniDumpWithTokenInformation = 0x00040000 }; #ifndef CONTEXT_ALL #define CONTEXT_ALL ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS ) #endif #pragma pack (pop) } // namespace Win32 #endif // TX_COMPILED #define FOREGROUND_BLACK ( 0 ) #define FOREGROUND_CYAN ( FOREGROUND_BLUE | FOREGROUND_GREEN ) #define FOREGROUND_MAGENTA ( FOREGROUND_BLUE | FOREGROUND_RED ) #define FOREGROUND_DARKYELLOW ( FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_LIGHTGRAY ( FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ) #define FOREGROUND_DARKGRAY ( FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTBLUE ( FOREGROUND_BLUE | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTGREEN ( FOREGROUND_GREEN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTCYAN ( FOREGROUND_CYAN | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTRED ( FOREGROUND_RED | FOREGROUND_INTENSITY ) #define FOREGROUND_LIGHTMAGENTA ( FOREGROUND_MAGENTA | FOREGROUND_INTENSITY ) #define FOREGROUND_YELLOW ( FOREGROUND_DARKYELLOW | FOREGROUND_INTENSITY ) #define FOREGROUND_WHITE ( FOREGROUND_LIGHTGRAY | FOREGROUND_INTENSITY ) #define BACKGROUND_BLACK ( 0 ) #define BACKGROUND_CYAN ( BACKGROUND_BLUE | BACKGROUND_GREEN ) #define BACKGROUND_MAGENTA ( BACKGROUND_BLUE | BACKGROUND_RED ) #define BACKGROUND_DARKYELLOW ( BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_GRAY ( BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED ) #define BACKGROUND_DARKGRAY ( BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTBLUE ( BACKGROUND_BLUE | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTGREEN ( BACKGROUND_GREEN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTCYAN ( BACKGROUND_CYAN | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTRED ( BACKGROUND_RED | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTMAGENTA ( BACKGROUND_MAGENTA | BACKGROUND_INTENSITY ) #define BACKGROUND_LIGHTYELLOW ( BACKGROUND_DARKYELLOW | BACKGROUND_INTENSITY ) #define BACKGROUND_WHITE ( BACKGROUND_DARKGRAY | BACKGROUND_INTENSITY ) //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ There are copies of MSVC compiler built-in predefined definitions, which are wrong in 64-bit mode. // So we have to override them. See: http://stackoverflow.com/questions/39113168 //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< #if defined (_MSC_VER) // MS ABI C++ Exception Layout namespace Win32 { // --------------------------- // #pragma pack (push, 4) // EXCEPTION_RECORD: // +==================================================+ struct ThrowInfo // |... | { // |NumberParameters: 3, 4 or more | __int32 attributes; // |ExceptionInformation[0]: MS signature 0x19930520 | __int32 pmfnUnwind; // |ExceptionInformation[1]: object* thrown | __int32 pForwardCompat; // |ExceptionInformation[2]: ThrowInfo* --------------+---+ __int32 pCatchableTypeArray; // |ExceptionInformation[3]: ImageBase (if params > 3)| | }; // +==================================================+ | // | struct CatchableTypeArray // ThrowInfo: | { // +======================================+ <-------+ __int32 nCatchableTypes; // | ... | __int32 arrayOfCatchableTypes[]; // +-----+-- pCatchableTypeArray (ptr/RVA) | }; // | +======================================+ // | struct CatchableType // | CatchableTypeArray: { // +---> +======================================+ __int32 properties; // | ... | __int32 pType; // +-----+-- arrayOfCatchableTypes[0] (ptr/RVA) | __int32 thisDisplacement[3]; // struct _PMD // | +======================================+ __int32 sizeOrOffset; // | __int32 copyFunction; // | CatchableType: }; // +---> +====================+ // | ... | std::type_info: #pragma pack (pop) // | pType (ptr/RVA) ---+------> +==================+ // | ... | |type_info data | } // namespace Win32 // +====================+ |... | // +==================+ #endif // Similar to __CxxDetectRethrow(), see C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\crtsrc\vcruntime\frame.cpp: #define _TX_MSC__CXX_DETECT_RETHROW( exc ) \ ( \ (exc) && \ (exc) -> ExceptionCode == EXCEPTION_CPP_MSC && \ (exc) -> NumberParameters >= 3 && \ \ ((exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || \ (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3) && \ \ (exc) -> ExceptionInformation[2] == 0 \ ) #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ The corresponding structures for GCC // // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h // See: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi //----------------------------------------------------------------------------------------------------------------- #if defined (_GCC_VER) #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // GCC ABI C++ Exception layout. A/B are ExceptionInformation[0]. namespace ABI { // -------------------------------------------------------------- // struct __cxa_exception // Case A: "_Unwind_Exception* A" is undependent exception: { // -------------------------------------------------------- union { // struct // __cxa_exception: std::type_info: { // -*--+====================+ +==================+ ::std::type_info* exceptionType; // ^ |exceptionType* -----+---->|type_info data | void (*exceptionDestructor)(void*); // | |... | |... | }; // -1 | | +==================+ struct // | | | { // A >----|--+--------------------+ __cxa_exception* primaryException; // | | |unwindHeader | void (*padding)(); // +1 | | | }; // | | | | }; // V | | | // -*--- +====================+ void (*unexpected_handler)(); // |object | std::terminate_handler terminateHandler; // +--------------------+ // __cxa_exception* nextException; // Case B: "_Unwind_Exception* B" is dependent exception int handlerCount; // (unwindHeader.exception_class & 1 != 0): int handlerSwitchValue; // ----------------------------------------------------- const unsigned char* actionRecord; // const unsigned char* languageSpecificData; // __cxa_exception: __cxa_exception: void* catchTemp; // -*--+====================+ -*--+=================+ void* adjustedPtr; // ^ |primaryException* --+-- ^ |exceptionType* | // | |... | \ | |... | _Unwind_Exception unwindHeader; // -1 | | | | | | }; // | | | | | | | // B >----|--+--------------------+ | -1 +-----------------+ struct __cxa_eh_globals // | | |unwindHeader | | | |unwindHeader | { // +1 | | | | | | | __cxa_exception* caughtExceptions; // | | | | | | | | unsigned int uncaughtExceptions; // V | | | \ | | | }; // -*--- +====================+ -->*--+=================+ // |... | |object | } // namespace ABI // . . | | // +-----------------+ extern "C" ABI::__cxa_eh_globals* __cxa_get_globals(); #endif // TX_COMPILED #endif //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Hand-made IAT. // Some IDEs don't link with these libs by default in console projects, so do sunrise by hand. :( //----------------------------------------------------------------------------------------------------------------- // Hand-made DLLIMPORT helpers #define _TX_DLLIMPORT( lib, retval, name, params ) TX_DLLIMPORT (true, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_OPT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, WINAPI) #define _TX_DLLIMPORT_CRT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, please) void (*_txDllImport (const char dllFileName[], const char funcName[], bool required = true)) (); //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< namespace Win32 { _TX_DLLIMPORT ("GDI32", HDC, CreateCompatibleDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateCompatibleBitmap, (HDC dc, int width, int height)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetStockObject, (int object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, SelectObject, (HDC dc, HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetCurrentObject, (HDC dc, unsigned objectType)); _TX_DLLIMPORT ("GDI32", int, GetObjectA, (HGDIOBJ obj, int bufsize, void* buffer)); _TX_DLLIMPORT ("GDI32", DWORD, GetObjectType, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", bool, DeleteDC, (HDC dc)); _TX_DLLIMPORT ("GDI32", bool, DeleteObject, (HGDIOBJ object)); _TX_DLLIMPORT ("GDI32", COLORREF, SetTextColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, SetBkColor, (HDC dc, COLORREF color)); _TX_DLLIMPORT ("GDI32", int, SetBkMode, (HDC dc, int bkMode)); _TX_DLLIMPORT ("GDI32", HFONT, CreateFontA, (int height, int width, int escapement, int orientation, int weight, DWORD italic, DWORD underline, DWORD strikeout, DWORD charSet, DWORD outputPrec, DWORD clipPrec, DWORD quality, DWORD pitchAndFamily, const char face[])); _TX_DLLIMPORT ("GDI32", int, EnumFontFamiliesExA, (HDC dc, LPLOGFONT logFont, FONTENUMPROC enumProc, LPARAM lParam, DWORD reserved)); _TX_DLLIMPORT ("GDI32", COLORREF, SetPixel, (HDC dc, int x, int y, COLORREF color)); _TX_DLLIMPORT ("GDI32", COLORREF, GetPixel, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", HPEN, CreatePen, (int penStyle, int width, COLORREF color)); _TX_DLLIMPORT ("GDI32", HBRUSH, CreateSolidBrush, (COLORREF color)); _TX_DLLIMPORT ("GDI32", bool, MoveToEx, (HDC dc, int x, int y, POINT* point)); _TX_DLLIMPORT ("GDI32", bool, LineTo, (HDC dc, int x, int y)); _TX_DLLIMPORT ("GDI32", bool, Polygon, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Polyline, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, PolyBezier, (HDC dc, const POINT points[], int count)); _TX_DLLIMPORT ("GDI32", bool, Rectangle, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, RoundRect, (HDC dc, int x0, int y0, int x1, int y1, int sizeX, int sizeY)); _TX_DLLIMPORT ("GDI32", bool, Ellipse, (HDC dc, int x0, int y0, int x1, int y1)); _TX_DLLIMPORT ("GDI32", bool, Arc, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Pie, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, Chord, (HDC dc, int x0, int y0, int x1, int y1, int xStart, int yStart, int xEnd, int yEnd)); _TX_DLLIMPORT ("GDI32", bool, TextOutA, (HDC dc, int x, int y, const char string[], int length)); _TX_DLLIMPORT ("GDI32", UINT, SetTextAlign, (HDC dc, unsigned mode)); _TX_DLLIMPORT ("GDI32", bool, GetTextExtentPoint32A, (HDC dc, const char string[], int length, SIZE* size)); _TX_DLLIMPORT ("GDI32", bool, ExtFloodFill, (HDC dc, int x, int y, COLORREF color, unsigned type)); _TX_DLLIMPORT ("GDI32", bool, BitBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, StretchBlt, (HDC dest, int xDest, int yDest, int width, int height, HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp)); _TX_DLLIMPORT ("GDI32", bool, PlgBlt, (HDC dest, const POINT* parallelogram, HDC src, int xSrc, int ySrc, int width, int height, HBITMAP mask, int xMask, int yMask)); _TX_DLLIMPORT ("GDI32", int, SetDIBitsToDevice, (HDC dc, int xDest, int yDest, DWORD width, DWORD height, int xSrc, int ySrc, unsigned startLine, unsigned numLines, const void* data, const BITMAPINFO* info, unsigned colorUse)); _TX_DLLIMPORT ("GDI32", int, GetDIBits, (HDC hdc, HBITMAP hbmp, unsigned uStartScan, unsigned cScanLines, void* lpvBits, BITMAPINFO* lpbi, unsigned usage)); _TX_DLLIMPORT ("GDI32", bool, PatBlt, (HDC dc, int x0, int y0, int width, int height, DWORD rOp)); _TX_DLLIMPORT ("GDI32", int, SetROP2, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", int, SetStretchBltMode, (HDC dc, int mode)); _TX_DLLIMPORT ("GDI32", DWORD, GdiSetBatchLimit, (DWORD limit)); _TX_DLLIMPORT ("GDI32", HBITMAP, CreateDIBSection, (HDC dc, const BITMAPINFO* bmInfo, unsigned colorUsage, void **vBits, HANDLE section, DWORD offset)); _TX_DLLIMPORT ("User32", int, DrawTextA, (HDC dc, const char text[], int length, RECT* rect, unsigned format)); _TX_DLLIMPORT ("User32", HANDLE, LoadImageA, (HINSTANCE inst, const char name[], unsigned type, int sizex, int sizey, unsigned mode)); _TX_DLLIMPORT_OPT ("User32", bool, IsHungAppWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", HWND, GhostWindowFromHungWindow, (HWND wnd)); _TX_DLLIMPORT_OPT ("User32", bool, FlashWindowEx, (const FLASHWINFO* flash)); _TX_DLLIMPORT ("WinMM", bool, PlaySound, (const char sound[], HMODULE mod, DWORD mode)); _TX_DLLIMPORT_OPT ("MSImg32", bool, TransparentBlt, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, unsigned transparentColor)); _TX_DLLIMPORT_OPT ("MSImg32", bool, AlphaBlend, (HDC dest, int destX, int destY, int destWidth, int destHeight, HDC src, int srcX, int srcY, int srcWidth, int srcHeight, BLENDFUNCTION blending)); _TX_DLLIMPORT ("Kernel32", void, ExitProcess, (unsigned retcode)); _TX_DLLIMPORT ("Kernel32", bool, TerminateProcess, (HANDLE process, unsigned retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalExit, (int retcode)); _TX_DLLIMPORT_OPT ("Kernel32", void, FatalAppExitA, (unsigned action, const char message[])); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetThreadId, (HANDLE thread)); _TX_DLLIMPORT ("Kernel32", HWND, GetConsoleWindow, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetConsoleFont, (HANDLE con, DWORD fontIndex)); _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetNumberOfConsoleFonts, (void)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFont, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFO* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont)); _TX_DLLIMPORT_OPT ("Kernel32", void, RtlCaptureContext, (CONTEXT* contextRecord)); _TX_DLLIMPORT_OPT ("Kernel32", USHORT, RtlCaptureStackBackTrace, (DWORD framesToSkip, DWORD framesToCapture, void** backTrace, DWORD* hash)); _TX_DLLIMPORT_OPT ("Kernel32", void*, AddVectoredExceptionHandler, (unsigned long firstHandler, PVECTORED_EXCEPTION_HANDLER handler)); _TX_DLLIMPORT_OPT ("Kernel32", unsigned, RemoveVectoredExceptionHandler,(void* handler)); _TX_DLLIMPORT_OPT ("Kernel32", bool, GetModuleHandleEx, (DWORD flags, const char moduleName[], HMODULE* module)); _TX_DLLIMPORT_OPT ("Kernel32", bool, IsWow64Process, (HANDLE process, int* isWow64Process)); _TX_DLLIMPORT_OPT ("Kernel32", bool, Wow64GetThreadContext, (HANDLE thread, WOW64_CONTEXT* context)); _TX_DLLIMPORT_OPT ("Kernel32", bool, SetThreadStackGuarantee, (unsigned long* stackSize)); _TX_DLLIMPORT ("OLE32", HRESULT, CoInitialize, (void*)); _TX_DLLIMPORT ("OLE32", HRESULT, CoCreateInstance, (REFCLSID clsId, IUnknown*, DWORD, REFIID iId, void** value)); _TX_DLLIMPORT ("OLE32", void, CoUninitialize, (void)); _TX_DLLIMPORT ("Shell32", HINSTANCE,ShellExecuteA, (HWND wnd, const char operation[], const char file[], const char parameters[], const char directory[], int showCmd)); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIA, (const char string[], const char search[])); _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIW, (const wchar_t string[], const wchar_t search[])); _TX_DLLIMPORT_OPT ("NTDLL", char*, wine_get_version, (void)); _TX_DLLIMPORT ("NTDLL", NTSTATUS, NtQueryInformationProcess, (HANDLE process, int infoClass, void* processInfo, unsigned long szProcessInfo, unsigned long* szReturnInfo)); _TX_DLLIMPORT_CRT ("MSVCRT", void, exit, (int retcode)); _TX_DLLIMPORT_CRT ("MSVCRT", void, _cexit, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _fpreset, (void)); _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _controlfp, (unsigned control, unsigned mask)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthread, (void (__cdecl* start_address) (void*), unsigned stack_size, void* arglist)); _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthreadex, (void* security, unsigned stack_size, unsigned (__stdcall* start_address) (void*), void *arglist, unsigned init_flag, unsigned* thread_addr)); _TX_DLLIMPORT_CRT ("MSVCRT", char*, __unDName, (char* outStr, const char* mangledName, int outStrLen, void* (*mallocFunc) (size_t size), void (*freeFunc) (void *pointer), unsigned short flags)); _TX_DLLIMPORT_CRT ("MSVCRT", unexpected_handler, set_unexpected, (unexpected_handler handler)); _TX_DLLIMPORT_OPT ("OpenGL32", HDC, wglGetCurrentDC, (void)); _TX_DLLIMPORT_OPT ("OpenGL32", unsigned, glGetError, (void)); _TX_DLLIMPORT_OPT ("Glu32", const char*, gluErrorString, (unsigned error)); _TX_DLLIMPORT_OPT ("ComDlg32", DWORD, CommDlgExtendedError, (void)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, MiniDumpWriteDump, (HANDLE process, DWORD processId, HANDLE file, MINIDUMP_TYPE dumpType, MINIDUMP_EXCEPTION_INFORMATION* exceptionParam, MINIDUMP_USER_STREAM_INFORMATION* userStreamParam, MINIDUMP_CALLBACK_INFORMATION* callbackParam)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("DbgHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("DbgHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); namespace MinGW { _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD, SymSetOptions, (DWORD options)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line)); _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymCleanup, (HANDLE process)); _TX_DLLIMPORT_OPT ("MgwHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase)); _TX_DLLIMPORT_OPT ("MgwHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord, PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc, PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc, PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc, PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc)); } // namespace MinGW } // namespace Win32 #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal function prototypes, macros and constants // @name Прототипы внутренних функций, макросы и константы //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize(); void _txCleanup(); HWND _txCanvas_CreateWindow (const SIZE* size); bool _txCanvas_OnCREATE (HWND wnd); bool _txCanvas_OnDESTROY (HWND wnd); bool _txCanvas_OnCLOSE (HWND); bool _txCanvas_OnPAINT (HWND wnd); bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down); bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info); bool _txCanvas_OnTIMER (HWND wnd, WPARAM id); bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords); bool _txCanvas_OnMOUSELEAVE (HWND wnd); bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd); bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd); unsigned WINAPI _txCanvas_ThreadProc (void* data); LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard; bool _txBuffer_Delete (HDC* dc); bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC()); HWND _txConsole_Attach(); bool _txConsole_OK() tx_nodiscard; bool _txConsole_Detach (bool activate); bool _txConsole_Draw (HDC dc); bool _txConsole_SetUnicodeFont(); const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra); HWND txCreateExtraWindow (CREATESTRUCT createData); HICON _txCreateTXIcon (int size) tx_nodiscard; int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL, int checkOfs = 0, const wchar_t checkLetters[2] = NULL); int _txPauseBeforeTermination (HWND canvas); int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard; void _txActivateWindow (HWND wnd, unsigned mode); int _txGetInput(); LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); const char* _txPlayVideo_FindVLC() tx_nodiscard; bool _txCreateShortcut (const char shortcutName[], const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL, const char description[] = NULL, int cmdShow = SW_SHOWNORMAL, const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0, COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD)); void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) tx_nodiscard; void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]); const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args); void _txOnTerminate(); void _txOnUnexpected(); void _txOnPureCall(); void _txOnNewHandlerAnsi(); int _txOnNewHandler (size_t size); void _txOnSignal (int signal = 0, int fpe = 0); BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type); void _txOnSecurityError (int code, void*); void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code); int _txOnMatherr (_exception* except); void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned line, uintptr_t); int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line); int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5); int _txOnErrorReport (int type, const char* text, int* ret); int tx_glGetError (int setError = INT_MIN); void _txOnCExit(); void _txOnExit (int retcode); void _txOnFatalExit (int retcode); void _txOnExitProcess (unsigned retcode); void _txOnFatalAppExitA (unsigned action, const char message[]); bool _txOnTerminateProcess (HANDLE process, unsigned retcode); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter); void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc); long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc); long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]); intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]); intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type); intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0, unsigned params = 0, const ULONG_PTR info[] = NULL); void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?", bool readSource = true); const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true, CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread()); int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL, HANDLE thread = GetCurrentThread()); const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false); const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2); bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL, Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL, const char** source = NULL, int context = 2); intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN); bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL); uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL, int useHotPatching = false, HMODULE module = NULL, bool debug = false); bool _txInDll() tx_nodiscard; PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard; bool _txKillProcess (DWORD pid); int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/); bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true); bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid()); IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard; bool _txIsConsoleSubsystem(); const char* _txAppInfo() tx_nodiscard; #if defined (_CLANG_VER) && !defined (_MSC_VER) void _txLibCppDebugFunction (std::__libcpp_debug_info const& info); #endif #endif // TX_COMPILED inline bool _txCanvas_OK () tx_nodiscard; int _txCanvas_SetRefreshLock (int count); const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0, const char msg[] = NULL, ...) tx_printfy (5); bool _txIsBadReadPtr (const void* address); intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3); intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg); bool _txIsTTY (int fd); void txReopenStdio(); #if defined (__CYGWIN__) int _getch(); int _putch (int ch); int _kbhit() tx_nodiscard; #endif //----------------------------------------------------------------------------------------------------------------- // There are macros for __FILE__ and __LINE__ to work properly. #if !defined (NDEBUG) #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \ (assert (cond), true) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Параметр \"%s\" неверен." \ " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка.", #dc), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (TX_ERROR ("\a" "%s" \ "Если вы указали параметр \"%s\", то он неверен.%s", \ (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \ #dc, \ ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка." : "")), 1) ) #else #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #endif //----------------------------------------------------------------------------------------------------------------- // Take action in debug configuration only. // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'( #if !defined (NDEBUG) #define _TX_ON_DEBUG( code ) { code; } #else #define _TX_ON_DEBUG( code ) ; #endif //----------------------------------------------------------------------------------------------------------------- // Invokes an error without location information. "$$" restores TX-related call location context #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__) //----------------------------------------------------------------------------------------------------------------- // Safe call of a function via its pointer #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 ) #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 ) //----------------------------------------------------------------------------------------------------------------- // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x. #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \ !(cond) && GetTickCount() < _t; \ Sleep (_txWindowUpdateInterval)) \ ; \ \ if (!(cond)) \ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); } //----------------------------------------------------------------------------------------------------------------- // Detouring in case of SEH mechanism #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 ) #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; } //----------------------------------------------------------------------------------------------------------------- // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code. #if defined (IN) // #undef IN #endif #if defined (OUT) // #undef OUT #endif //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal global data //! @name Внутренние глобальные данные // // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :) // // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же. // Здесь это сделано только в образовательных целях. // // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс. //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<< const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна _TX_IDM_CONSOLE = 40001, _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas //----------------------------------------------------------------------------------------------------------------- volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize(); volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main() volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT() RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0] HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP), // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock() UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question. int _txConsole = false; // Only first TXLib module in app can own the console bool _txMain = false; // First TXLib wnd opened (closing it terminates program) bool _txIsDll = false; // TXLib module is in DLL volatile bool _txRunning = false; // main() is still running volatile bool _txExit = false; // exit() is active volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE() volatile unsigned _txMouseButtons = 0; volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook(). _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro volatile int _txErrors = 0; // TX_ERROR calls sequental number volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError() volatile long _txSENumber = 0; // SEH exceptions sequental number volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess, (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA, (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp, (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier, (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler, (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace, (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize, (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions, (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64, (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr, (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup, (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64, (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64, (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64, (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext }; volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- extern volatile unsigned _txCanaryFirst; extern volatile unsigned _txCanaryLast; extern volatile HWND _txCanvas_Window; extern volatile unsigned _txCanvas_ThreadId; extern HDC _txCanvas_BackBuf[2]; extern RGBQUAD* _txCanvas_Pixels; extern volatile int _txCanvas_RefreshLock; extern volatile WNDPROC _txAltWndProc; extern volatile bool _txExit; extern volatile int _txOGLError; //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib engine init/check/cleanup //! @name Инициализация/проверка/завершение TXLib //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Early initialization //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize() { if (_txInitialized) return 1; _txInitialized = 1; #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585 #endif #if defined (_TX_ALLOW_TRACE) _txLocLvlSet (1); #endif _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" " "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n"); OutputDebugString ("\n")); _txMainThreadId = GetCurrentThreadId(); _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId); $3 _txIsDll = _txInDll(); $ if (!_txIsDll) { $ _txConsole = ! FindAtom ("_txConsole"); $ (void) AddAtom ("_txConsole"); //-V530 } $ if (_txConsole) { $ _txCheckSourceCP (_TX_CODEPAGE, true); $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ _txOnSignal(); $ if (!*_txLogName) {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); } $ if (!_txIsDll) { $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler)); $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter); } $ ::std::set_terminate (_txOnTerminate); $ ::std::set_new_handler (_txOnNewHandlerAnsi); $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected)); #if defined (_CLANG_VER) && !defined (_MSC_VER) $ ::std::__libcpp_debug_function = _txLibCppDebugFunction; #endif $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true); $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #if defined (_MSC_VER) $ _set_printf_count_output (1); $ _set_new_handler (_txOnNewHandler); $ _set_new_mode (1); #if !defined (_CLANG_VER) $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); $ _CrtSetAllocHook (_txOnAllocHook); $ unsigned mode = _CRTDBG_MODE_FILE; $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0; $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode); $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG); $ _set_abort_behavior (0, _CALL_REPORTFAULT); $ _RTC_SetErrorFunc (_txOnRTCFailure); $ _set_purecall_handler (_txOnPureCall); $ _set_invalid_parameter_handler (_txOnInvalidParam); #endif #if defined (__STDC_LIB_EXT1__) $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi); #endif #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386) $ __setusermatherr (_txOnMatherr); #endif #if !defined (__CYGWIN__) $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR); #endif $ HWND console = _txConsole_Attach(); $ SetWindowTextA (console, txGetModuleFileName (false)); } $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL"); $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL"); $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit); $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit); $ InitializeCriticalSection (&_txCanvas_LockBackBuf); $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted; $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted; $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted; $ Win32::DeleteDC (dc) asserted; $ atexit (_txCleanup); $ if (_txConsole) { $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ tx_fpreset(); $ srand ((unsigned) time (NULL)); //-V202 $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif } $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used" $ return 1; } //----------------------------------------------------------------------------------------------------------------- bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/) { $3 const char* sCodePage = NULL; $ int codePage = 0; $ switch (((unsigned const char*) "А") [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
6953  // при выходе из функции и строка в нем, соответственно, тоже. Адрес нестатических переменных передавать
6954  // синтаксически можно, но ведет к серьезным ошибкам.
6955  //-------------------------------------------------------------------------------------------------------------
6956 
6957  return dlg.str;
6958  }
6959 
6960 #endif // TX_COMPILED
6961 
6963 //}
6964 //=================================================================================================================
6965 
6966 //}
6967 //=================================================================================================================
6968 
6969 //=================================================================================================================
6970 //{ TXLIB IMPLEMENTATION
6971 // Реализация функций библиотеки
6972 //=================================================================================================================
6974 
6975 //-----------------------------------------------------------------------------------------------------------------
6976 //{ The Includes
6977 //-----------------------------------------------------------------------------------------------------------------
6978 
6979 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
6980 
6981 _TX_END_NAMESPACE
6982 
6983 //-----------------------------------------------------------------------------------------------------------------
6984 
6985 #if defined (_MSC_VER)
6986  #pragma warning (push, 3) // MSVC: At level /Wall, some std headers emit warnings... O_o
6987 
6988  #pragma warning (disable: 4365) // 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch
6989  #pragma warning (disable: 4005) // 'name': macro redefinition
6990 #endif
6991 
6992 #if defined (__STRICT_ANSI__) && defined (__STRICT_ANSI__UNDEFINED)
6993  #undef __STRICT_ANSI__
6994 #endif
6995 
6996 //-----------------------------------------------------------------------------------------------------------------
6997 
6998 #include <stdarg.h>
6999 #include <io.h>
7000 #include <fcntl.h>
7001 #include <process.h>
7002 #include <signal.h>
7003 #include <setjmp.h>
7004 #include <locale.h>
7005 #include <limits.h>
7006 #include <stdint.h>
7007 
7008 #include <map>
7009 #include <numeric>
7010 #include <exception>
7011 #include <stdexcept>
7012 
7013 #include <tlhelp32.h>
7014 #include <shellapi.h>
7015 
7016 #if defined (_GCC_VER)
7017 
7018 #include <shlobj.h>
7019 
7020 #include <cxxabi.h>
7021 #include <unwind.h>
7022 
7023 #endif
7024 
7025 #if defined (__CYGWIN__)
7026 
7027 #include <stdarg.h>
7028 #include <unistd.h>
7029 #include <termios.h>
7030 
7031 #endif
7032 
7033 #if defined (_MSC_VER)
7034 
7035 #include <new.h>
7036 
7037 #include <shlobj.h>
7038 #include <ntstatus.h>
7039 #include <crtdbg.h>
7040 #include <rtcapi.h>
7041 #include <dbghelp.h>
7042 
7043 #endif
7044 
7045 #if defined (_GCC_VER) || defined (_MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013
7046 #include <inttypes.h>
7047 #endif
7048 
7049 //-----------------------------------------------------------------------------------------------------------------
7050 
7051 #if defined (TX_USE_SPEAK) //--------------------------------------------------------------------------------------
7052 #include <SAPI.h> // <== ЕСЛИ ЗДЕСЬ ОШИБКА, ТО У ВАС НЕТ ФАЙЛА SAPI.h. No SAPI.h file, TXLib isn't guilty :(
7053 #endif //--------------------------------------------------------------------------------------
7054 
7055 //-----------------------------------------------------------------------------------------------------------------
7056 
7057 #if defined (_MSC_VER)
7058  #pragma warning (pop) // MSVC: Restore max level
7059 #endif
7060 
7061 #if defined (__STRICT_ANSI__UNDEFINED)
7062  #define __STRICT_ANSI__ // Redefine back
7063 #endif
7064 
7065 //-----------------------------------------------------------------------------------------------------------------
7066 
7067 _TX_BEGIN_NAMESPACE
7068 
7069 #endif // TX_COMPILED
7070 
7071 //}
7072 //-----------------------------------------------------------------------------------------------------------------
7073 
7074 //=================================================================================================================
7075 //{ DLL functions import, missing types definitions
7077 //=================================================================================================================
7079 
7080 //-----------------------------------------------------------------------------------------------------------------
7081 //{ Some of structs, consts and interfaces aren't defined in MinGW some early headers.
7082 // Copied from Windows SDK 7.0a.
7083 //-----------------------------------------------------------------------------------------------------------------
7084 
7085 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
7086 
7087 namespace Win32 {
7088 
7089 #ifndef AC_SRC_ALPHA
7090 #define AC_SRC_ALPHA 0x01
7091 #endif
7092 
7093 #ifndef SMTO_ERRORONEXIT
7094 #define SMTO_ERRORONEXIT 0x0020
7095 #endif
7096 
7097 #ifndef NT_CONSOLE_PROPS_SIG
7098 #define NT_CONSOLE_PROPS_SIG 0xA0000002
7099 #endif
7100 
7101 #ifndef NIIF_INFO
7102 #define NIIF_INFO 0x00000001
7103 #define NIIF_WARNING 0x00000002
7104 #define NIIF_ERROR 0x00000003
7105 #endif
7106 
7107 #ifndef NIF_INFO
7108 #define NIF_STATE 0x00000008
7109 #define NIF_INFO 0x00000010
7110 #endif
7111 
7112 #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
7113 #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004
7114 #endif
7115 
7116 #ifndef SYMOPT_CASE_INSENSITIVE
7117 #define SYMOPT_CASE_INSENSITIVE 0x00000001
7118 #define SYMOPT_UNDNAME 0x00000002
7119 #define SYMOPT_DEFERRED_LOADS 0x00000004
7120 #define SYMOPT_NO_CPP 0x00000008
7121 #define SYMOPT_LOAD_LINES 0x00000010
7122 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020
7123 #define SYMOPT_LOAD_ANYTHING 0x00000040
7124 #define SYMOPT_IGNORE_CVREC 0x00000080
7125 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100
7126 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200
7127 #define SYMOPT_EXACT_SYMBOLS 0x00000400
7128 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800
7129 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000
7130 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000
7131 #define SYMOPT_PUBLICS_ONLY 0x00004000
7132 #define SYMOPT_NO_PUBLICS 0x00008000
7133 #define SYMOPT_AUTO_PUBLICS 0x00010000
7134 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000
7135 #define SYMOPT_SECURE 0x00040000
7136 #define SYMOPT_NO_PROMPTS 0x00080000
7137 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000
7138 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000
7139 #define SYMOPT_FAVOR_COMPRESSED 0x00800000
7140 #define SYMOPT_FLAT_DIRECTORY 0x00400000
7141 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000
7142 #define SYMOPT_OVERWRITE 0x00100000
7143 #define SYMOPT_DEBUG 0x80000000
7144 #endif
7145 
7146 // SEH exception codes. For GCC, see http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 64-66.
7147 
7148 #ifndef STATUS_POSSIBLE_DEADLOCK
7149 #define STATUS_POSSIBLE_DEADLOCK 0xC0000194
7150 #endif
7151 
7152 #ifndef STATUS_FLOAT_MULTIPLE_FAULTS
7153 #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4
7154 #endif
7155 
7156 #ifndef STATUS_STACK_BUFFER_OVERRUN
7157 #define STATUS_STACK_BUFFER_OVERRUN 0xC0000409
7158 #endif
7159 
7160 #ifndef STATUS_ASSERTION_FAILURE
7161 #define STATUS_ASSERTION_FAILURE 0xC0000420
7162 #endif
7163 
7164 #ifndef STATUS_WX86_BREAKPOINT
7165 #define STATUS_WX86_BREAKPOINT 0x4000001F
7166 #endif
7167 
7168 #ifndef DBG_PRINTEXCEPTION_C
7169 #define DBG_PRINTEXCEPTION_C 0x40010006 // OutputDebugStringA() call
7170 #endif
7171 
7172 #ifndef DBG_PRINTEXCEPTION_WIDE_C
7173 #define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A // OutputDebugStringW() call
7174 #endif
7175 
7176 #ifndef DBG_THREAD_NAME
7177 #define DBG_THREAD_NAME 0x406D1388
7178 #endif
7179 
7180 #define EXCEPTION_CPP_MSC 0xE06D7363 // '?msc'
7181 #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 0x19930520 // '?msc' version magic, see ehdata.h
7182 #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 0x19930521 // '?msc' version magic
7183 #define EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 0x19930522 // '?msc' version magic
7184 #define EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1 0x01994000 // '?msc' version magic
7185 
7186 #define EXCEPTION_CPP_GCC 0x20474343 // ' GCC'
7187 #define EXCEPTION_CPP_GCC_UNWIND 0x21474343 // '!GCC'
7188 #define EXCEPTION_CPP_GCC_FORCED 0x22474343 // '"GCC'
7189 
7190 #define EXCEPTION_CLR_FAILURE 0xE0434f4D // 'аCOM'
7191 
7192 #define EXCEPTION_CPP_BORLAND_BUILDER 0x0EEDFAE6 // Should never occur here
7193 #define EXCEPTION_CPP_BORLAND_DELPHI 0x0EEDFADE // Should never occur here
7194 
7195 #pragma pack (push, 1)
7196 
7197 struct CONSOLE_CURSOR_INFO
7198  {
7199  DWORD dwSize;
7200  BOOL bVisible;
7201  };
7202 
7203 struct CONSOLE_FONT_INFO
7204  {
7205  DWORD nFont;
7206  COORD dwFontSize;
7207  };
7208 
7209 struct CONSOLE_FONT_INFOEX
7210  {
7211  ULONG cbSize;
7212  DWORD nFont;
7213  COORD dwFontSize;
7214  UINT FontFamily;
7215  UINT FontWeight;
7216  WCHAR FaceName[LF_FACESIZE];
7217  };
7218 
7219 struct DATABLOCK_HEADER
7220  {
7221  DWORD cbSize;
7222  DWORD dwSignature;
7223  };
7224 
7225 struct NT_CONSOLE_PROPS
7226  {
7227  DATABLOCK_HEADER dbh;
7228 
7229  WORD wFillAttribute;
7230  WORD wPopupFillAttribute;
7231  COORD dwScreenBufferSize;
7232  COORD dwWindowSize;
7233  COORD dwWindowOrigin;
7234  DWORD nFont;
7235  DWORD nInputBufferSize;
7236  COORD dwFontSize;
7237  UINT uFontFamily;
7238  UINT uFontWeight;
7239  WCHAR FaceName[LF_FACESIZE];
7240  UINT uCursorSize;
7241  BOOL bFullScreen;
7242  BOOL bQuickEdit;
7243  BOOL bInsertMode;
7244  BOOL bAutoPosition;
7245  UINT uHistoryBufferSize;
7246  UINT uNumberOfHistoryBuffers;
7247  BOOL bHistoryNoDup;
7248 
7249  COLORREF ColorTable[16];
7250  };
7251 
7252 struct FLASHWINFO
7253  {
7254  UINT cbSize;
7255  HWND hwnd;
7256  DWORD dwFlags;
7257  UINT uCount;
7258  DWORD dwTimeout;
7259  };
7260 
7261 enum TBPFLAG
7262  {
7263  TBPF_NOPROGRESS = 0x0,
7264  TBPF_INDETERMINATE = 0x1,
7265  TBPF_NORMAL = 0x2,
7266  TBPF_ERROR = 0x4,
7267  TBPF_PAUSED = 0x8
7268  };
7269 
7270 #pragma pack (pop)
7271 
7272 const GUID IID_IShellLink = {0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
7273 const GUID IID_IShellLinkDataList = {0x45e2b4ae, 0xb1c3, 0x11d0, {0xb9,0x2f,0x00,0xa0,0xc9,0x03,0x12,0xe1}};
7274 const GUID IID_IPersistFile = {0x0000010b, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
7275 
7276 const GUID IID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}};
7277 const GUID CLSID_TaskbarList = {0x56fdf344, 0xfd6d, 0x11d0, {0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}};
7278 
7279 const GUID CLSID_SpVoice = {0x96749377, 0x3391, 0x11d2, {0x9e,0xe3,0x00,0xc0,0x4f,0x79,0x73,0x96}};
7280 const GUID IID_ISpVoice = {0x6c44df74, 0x72b9, 0x4992, {0xa1,0xec,0xef,0x99,0x6e,0x04,0x22,0xd4}};
7281 
7282 typedef DWORD NTSTATUS;
7283 typedef ULONG_PTR KAFFINITY;
7284 typedef LONG KPRIORITY;
7285 
7286 struct UNICODE_STRING
7287  {
7288  USHORT Length;
7289  USHORT MaximumLength;
7290  wchar_t* Buffer;
7291  };
7292 
7293 struct RTL_DRIVE_LETTER_CURDIR
7294  {
7295  USHORT Flags;
7296  USHORT Length;
7297  ULONG TimeStamp;
7298  UNICODE_STRING DosPath;
7299  };
7300 
7301 struct CURDIR
7302  {
7303  UNICODE_STRING DosPath;
7304  void* Handle;
7305  };
7306 
7307 struct RTL_USER_PROCESS_PARAMETERS
7308  {
7309  ULONG AllocationSize;
7310  ULONG Size;
7311  ULONG Flags;
7312  ULONG DebugFlags;
7313  HANDLE ConsoleHandle;
7314  ULONG ConsoleFlags;
7315  HANDLE hStdInput;
7316  HANDLE hStdOutput;
7317  HANDLE hStdError;
7318  CURDIR CurrentDirectory;
7319  UNICODE_STRING DllPath;
7320  UNICODE_STRING ImagePathName;
7321  UNICODE_STRING CommandLine;
7322  wchar_t* Environment;
7323  ULONG dwX;
7324  ULONG dwY;
7325  ULONG dwXSize;
7326  ULONG dwYSize;
7327  ULONG dwXCountChars;
7328  ULONG dwYCountChars;
7329  ULONG dwFillAttribute;
7330  ULONG dwFlags;
7331  ULONG wShowWindow;
7332  UNICODE_STRING WindowTitle;
7333  UNICODE_STRING Desktop;
7334  UNICODE_STRING ShellInfo;
7335  UNICODE_STRING RuntimeInfo;
7336  RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
7337  };
7338 
7339 struct PEB
7340  {
7341  BYTE Reserved1[2];
7342  BYTE BeingDebugged;
7343  BYTE Reserved2[1];
7344  void* Reserved3[2];
7345  void* Ldr;
7346  RTL_USER_PROCESS_PARAMETERS* ProcessParameters;
7347  void* Reserved4[3];
7348  void* AtlThunkSListPtr;
7349  void* Reserved5;
7350  ULONG Reserved6;
7351  void* Reserved7;
7352  ULONG Reserved8;
7353  ULONG AtlThunkSListPtr32;
7354  void* Reserved9[45];
7355  BYTE Reserved10[96];
7356  void* PostProcessInitRoutine;
7357  BYTE Reserved11[128];
7358  void* Reserved12[1];
7359  ULONG SessionId;
7360  };
7361 
7362 struct TEB
7363  {
7364  void* Reserved1[12];
7365  PEB* ProcessEnvironmentBlock;
7366  void* Reserved2[399];
7367  BYTE Reserved3[1952];
7368  void* TlsSlots[64];
7369  BYTE Reserved4[8];
7370  void* Reserved5[26];
7371  void* ReservedForOle;
7372  void* Reserved6[4];
7373  void* TlsExpansionSlots;
7374  };
7375 
7376 struct PROCESS_BASIC_INFORMATION
7377  {
7378  NTSTATUS ExitStatus;
7379  PEB* PebBaseAddress;
7380  KAFFINITY AffinityMask;
7381  KPRIORITY BasePriority;
7382  ULONG_PTR UniqueProcessId;
7383  ULONG_PTR InheritedFromUniqueProcessId;
7384  };
7385 
7386 enum ADDRESS_MODE
7387  {
7388  AddrMode1616,
7389  AddrMode1632,
7390  AddrModeReal,
7391  AddrModeFlat
7392  };
7393 
7394 struct ADDRESS64
7395  {
7396  DWORD64 Offset;
7397  WORD Segment;
7398  ADDRESS_MODE Mode;
7399  };
7400 
7401 struct KDHELP64
7402  {
7403  DWORD64 Thread;
7404  DWORD ThCallbackStack;
7405  DWORD ThCallbackBStore;
7406  DWORD NextCallback;
7407  DWORD FramePointer;
7408  DWORD64 KiCallUserMode;
7409  DWORD64 KeUserCallbackDispatcher;
7410  DWORD64 SystemRangeStart;
7411  DWORD64 KiUserExceptionDispatcher;
7412  DWORD64 StackBase;
7413  DWORD64 StackLimit;
7414  DWORD64 Reserved[5];
7415  };
7416 
7417 struct STACKFRAME64
7418  {
7419  ADDRESS64 AddrPC;
7420  ADDRESS64 AddrReturn;
7421  ADDRESS64 AddrFrame;
7422  ADDRESS64 AddrStack;
7423  ADDRESS64 AddrBStore;
7424  void* FuncTableEntry;
7425  DWORD64 Params[4];
7426  BOOL Far;
7427  BOOL Virtual;
7428  DWORD64 Reserved[3];
7429  KDHELP64 KdHelp;
7430  };
7431 
7432 struct WOW64_FLOATING_SAVE_AREA
7433  {
7434  DWORD ControlWord;
7435  DWORD StatusWord;
7436  DWORD TagWord;
7437  DWORD ErrorOffset;
7438  DWORD ErrorSelector;
7439  DWORD DataOffset;
7440  DWORD DataSelector;
7441  BYTE RegisterArea[80];
7442  DWORD Cr0NpxState;
7443  };
7444 
7445 #pragma pack (push, 4)
7446 
7447 struct WOW64_CONTEXT
7448  {
7449  DWORD ContextFlags;
7450 
7451  DWORD Dr0;
7452  DWORD Dr1;
7453  DWORD Dr2;
7454  DWORD Dr3;
7455  DWORD Dr6;
7456  DWORD Dr7;
7457 
7458  WOW64_FLOATING_SAVE_AREA FloatSave;
7459 
7460  DWORD SegGs;
7461  DWORD SegFs;
7462  DWORD SegEs;
7463  DWORD SegDs;
7464 
7465  DWORD Edi;
7466  DWORD Esi;
7467  DWORD Ebx;
7468  DWORD Edx;
7469  DWORD Ecx;
7470  DWORD Eax;
7471 
7472  DWORD Ebp;
7473  DWORD Eip;
7474  DWORD SegCs;
7475  DWORD EFlags;
7476  DWORD Esp;
7477  DWORD SegSs;
7478 
7479  BYTE ExtendedRegisters[512];
7480  };
7481 
7482 #pragma pack (pop)
7483 
7484 struct SYMBOL_INFO
7485  {
7486  ULONG SizeOfStruct;
7487  ULONG TypeIndex;
7488  ULONG64 Reserved[2];
7489  ULONG info;
7490  ULONG Size;
7491  ULONG64 ModBase;
7492  ULONG Flags;
7493  ULONG64 Value;
7494  ULONG64 Address;
7495  ULONG Register;
7496  ULONG Scope;
7497  ULONG Tag;
7498  ULONG NameLen;
7499  ULONG MaxNameLen;
7500  char Name[1];
7501  };
7502 
7503 struct IMAGEHLP_LINE64
7504  {
7505  DWORD SizeOfStruct;
7506  void* Key;
7507  DWORD LineNumber;
7508  char* FileName;
7509  DWORD64 Address;
7510  };
7511 
7512 typedef bool (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64) (HANDLE process, DWORD64 baseAddress, void* buffer, DWORD size, DWORD* bytesRead);
7513 typedef void* (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64) (HANDLE process, DWORD64 baseAddress);
7514 typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64) (HANDLE process, DWORD64 address);
7515 typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64) (HANDLE process, HANDLE thread, ADDRESS64* address);
7516 
7517 typedef void (*unexpected_handler)();
7518 
7519 #pragma pack (push, 4)
7520 
7521 struct MINIDUMP_THREAD_CALLBACK
7522  {
7523  ULONG ThreadId;
7524  HANDLE ThreadHandle;
7525  CONTEXT Context;
7526  ULONG SizeOfContext;
7527  ULONG64 StackBase;
7528  ULONG64 StackEnd;
7529  };
7530 
7531 struct MINIDUMP_THREAD_EX_CALLBACK
7532  {
7533  ULONG ThreadId;
7534  HANDLE ThreadHandle;
7535  CONTEXT Context;
7536  ULONG SizeOfContext;
7537  ULONG64 StackBase;
7538  ULONG64 StackEnd;
7539  ULONG64 BackingStoreBase;
7540  ULONG64 BackingStoreEnd;
7541  };
7542 
7543 struct MINIDUMP_MODULE_CALLBACK
7544  {
7545  wchar_t* FullPath;
7546  ULONG64 BaseOfImage;
7547  ULONG SizeOfImage;
7548  ULONG CheckSum;
7549  ULONG TimeDateStamp;
7550  VS_FIXEDFILEINFO VersionInfo;
7551  void* CvRecord;
7552  ULONG SizeOfCvRecord;
7553  void* MiscRecord;
7554  ULONG SizeOfMiscRecord;
7555  };
7556 
7557 struct MINIDUMP_INCLUDE_THREAD_CALLBACK
7558  {
7559  ULONG ThreadId;
7560  };
7561 
7562 struct MINIDUMP_INCLUDE_MODULE_CALLBACK
7563  {
7564  ULONG64 BaseOfImage;
7565  };
7566 
7567 struct MINIDUMP_MEMORY_INFO
7568  {
7569  ULONG64 BaseAddress;
7570  ULONG64 AllocationBase;
7571  ULONG32 AllocationProtect;
7572  ULONG32 __alignment1;
7573  ULONG64 RegionSize;
7574  ULONG32 State;
7575  ULONG32 Protect;
7576  ULONG32 Type;
7577  ULONG32 __alignment2;
7578  };
7579 
7580 struct MINIDUMP_USER_STREAM
7581  {
7582  ULONG32 Type;
7583  ULONG BufferSize;
7584  void* Buffer;
7585  };
7586 
7587 struct MINIDUMP_USER_STREAM_INFORMATION
7588  {
7589  ULONG UserStreamCount;
7590  MINIDUMP_USER_STREAM* UserStreamArray;
7591  };
7592 
7593 struct MINIDUMP_CALLBACK_INPUT
7594  {
7595  ULONG ProcessId;
7596  HANDLE ProcessHandle;
7597  ULONG CallbackType;
7598 
7599  union //-V2514
7600  {
7601  MINIDUMP_THREAD_CALLBACK Thread;
7602  MINIDUMP_THREAD_EX_CALLBACK ThreadEx;
7603  MINIDUMP_MODULE_CALLBACK Module;
7604  MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread;
7605  MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule;
7606  };
7607  };
7608 
7609 struct MINIDUMP_CALLBACK_OUTPUT
7610  {
7611  union //-V2514
7612  {
7613  ULONG ModuleWriteFlags;
7614  ULONG ThreadWriteFlags;
7615  ULONG SecondaryFlags;
7616 
7617  struct
7618  {
7619  ULONG64 MemoryBase;
7620  ULONG MemorySize;
7621  };
7622 
7623  struct
7624  {
7625  unsigned CheckCancel;
7626  unsigned Cancel;
7627  };
7628 
7629  HANDLE Handle; //-V117
7630  };
7631 
7632  struct
7633  {
7634  MINIDUMP_MEMORY_INFO VmRegion;
7635  unsigned Continue;
7636  };
7637 
7638  HRESULT Status;
7639  };
7640 
7641 struct MINIDUMP_EXCEPTION_INFORMATION
7642  {
7643  DWORD ThreadId;
7644  EXCEPTION_POINTERS* ExceptionPointers;
7645  unsigned ClientPointers;
7646  };
7647 
7648 typedef int (WINAPI* MINIDUMP_CALLBACK_ROUTINE) (void* param, MINIDUMP_CALLBACK_INPUT* input, MINIDUMP_CALLBACK_OUTPUT* output);
7649 
7650 struct MINIDUMP_CALLBACK_INFORMATION
7651  {
7652  MINIDUMP_CALLBACK_ROUTINE CallbackRoutine;
7653  void* CallbackParam;
7654  };
7655 
7656 enum MINIDUMP_TYPE
7657  {
7658  MiniDumpNormal = 0x00000000,
7659  MiniDumpWithDataSegs = 0x00000001,
7660  MiniDumpWithFullMemory = 0x00000002,
7661  MiniDumpWithHandleData = 0x00000004,
7662  MiniDumpFilterMemory = 0x00000008,
7663  MiniDumpScanMemory = 0x00000010,
7664  MiniDumpWithUnloadedModules = 0x00000020,
7665  MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
7666  MiniDumpFilterModulePaths = 0x00000080,
7667  MiniDumpWithProcessThreadData = 0x00000100,
7668  MiniDumpWithPrivateReadWriteMemory = 0x00000200,
7669  MiniDumpWithoutOptionalData = 0x00000400,
7670  MiniDumpWithFullMemoryInfo = 0x00000800,
7671  MiniDumpWithThreadInfo = 0x00001000,
7672  MiniDumpWithCodeSegs = 0x00002000,
7673  MiniDumpWithoutAuxiliaryState = 0x00004000,
7674  MiniDumpWithFullAuxiliaryState = 0x00008000,
7675  MiniDumpWithPrivateWriteCopyMemory = 0x00010000,
7676  MiniDumpIgnoreInaccessibleMemory = 0x00020000,
7677  MiniDumpWithTokenInformation = 0x00040000
7678  };
7679 
7680 #ifndef CONTEXT_ALL
7681 #define CONTEXT_ALL ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS )
7682 #endif
7683 
7684 #pragma pack (pop)
7685 
7686 } // namespace Win32
7687 
7688 #endif // TX_COMPILED
7689 
7690 #define FOREGROUND_BLACK ( 0 )
7691 #define FOREGROUND_CYAN ( FOREGROUND_BLUE | FOREGROUND_GREEN )
7692 #define FOREGROUND_MAGENTA ( FOREGROUND_BLUE | FOREGROUND_RED )
7693 #define FOREGROUND_DARKYELLOW ( FOREGROUND_GREEN | FOREGROUND_RED )
7694 #define FOREGROUND_LIGHTGRAY ( FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED )
7695 #define FOREGROUND_DARKGRAY ( FOREGROUND_INTENSITY )
7696 #define FOREGROUND_LIGHTBLUE ( FOREGROUND_BLUE | FOREGROUND_INTENSITY )
7697 #define FOREGROUND_LIGHTGREEN ( FOREGROUND_GREEN | FOREGROUND_INTENSITY )
7698 #define FOREGROUND_LIGHTCYAN ( FOREGROUND_CYAN | FOREGROUND_INTENSITY )
7699 #define FOREGROUND_LIGHTRED ( FOREGROUND_RED | FOREGROUND_INTENSITY )
7700 #define FOREGROUND_LIGHTMAGENTA ( FOREGROUND_MAGENTA | FOREGROUND_INTENSITY )
7701 #define FOREGROUND_YELLOW ( FOREGROUND_DARKYELLOW | FOREGROUND_INTENSITY )
7702 #define FOREGROUND_WHITE ( FOREGROUND_LIGHTGRAY | FOREGROUND_INTENSITY )
7703 
7704 #define BACKGROUND_BLACK ( 0 )
7705 #define BACKGROUND_CYAN ( BACKGROUND_BLUE | BACKGROUND_GREEN )
7706 #define BACKGROUND_MAGENTA ( BACKGROUND_BLUE | BACKGROUND_RED )
7707 #define BACKGROUND_DARKYELLOW ( BACKGROUND_GREEN | BACKGROUND_RED )
7708 #define BACKGROUND_GRAY ( BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED )
7709 #define BACKGROUND_DARKGRAY ( BACKGROUND_INTENSITY )
7710 #define BACKGROUND_LIGHTBLUE ( BACKGROUND_BLUE | BACKGROUND_INTENSITY )
7711 #define BACKGROUND_LIGHTGREEN ( BACKGROUND_GREEN | BACKGROUND_INTENSITY )
7712 #define BACKGROUND_LIGHTCYAN ( BACKGROUND_CYAN | BACKGROUND_INTENSITY )
7713 #define BACKGROUND_LIGHTRED ( BACKGROUND_RED | BACKGROUND_INTENSITY )
7714 #define BACKGROUND_LIGHTMAGENTA ( BACKGROUND_MAGENTA | BACKGROUND_INTENSITY )
7715 #define BACKGROUND_LIGHTYELLOW ( BACKGROUND_DARKYELLOW | BACKGROUND_INTENSITY )
7716 #define BACKGROUND_WHITE ( BACKGROUND_DARKGRAY | BACKGROUND_INTENSITY )
7717 
7718 //}
7719 //-----------------------------------------------------------------------------------------------------------------
7720 
7721 //-----------------------------------------------------------------------------------------------------------------
7722 //{ There are copies of MSVC compiler built-in predefined definitions, which are wrong in 64-bit mode.
7723 // So we have to override them. See: http://stackoverflow.com/questions/39113168
7724 //-----------------------------------------------------------------------------------------------------------------
7725 
7726 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
7727 
7728 #if defined (_MSC_VER)
7729  // MS ABI C++ Exception Layout
7730 namespace Win32 { // ---------------------------
7731  //
7732 #pragma pack (push, 4) // EXCEPTION_RECORD:
7733  // +==================================================+
7734 struct ThrowInfo // |... |
7735  { // |NumberParameters: 3, 4 or more |
7736  __int32 attributes; // |ExceptionInformation[0]: MS signature 0x19930520 |
7737  __int32 pmfnUnwind; // |ExceptionInformation[1]: object* thrown |
7738  __int32 pForwardCompat; // |ExceptionInformation[2]: ThrowInfo* --------------+---+
7739  __int32 pCatchableTypeArray; // |ExceptionInformation[3]: ImageBase (if params > 3)| |
7740  }; // +==================================================+ |
7741  // |
7742 struct CatchableTypeArray // ThrowInfo: |
7743  { // +======================================+ <-------+
7744  __int32 nCatchableTypes; // | ... |
7745  __int32 arrayOfCatchableTypes[]; // +-----+-- pCatchableTypeArray (ptr/RVA) |
7746  }; // | +======================================+
7747  // |
7748 struct CatchableType // | CatchableTypeArray:
7749  { // +---> +======================================+
7750  __int32 properties; // | ... |
7751  __int32 pType; // +-----+-- arrayOfCatchableTypes[0] (ptr/RVA) |
7752  __int32 thisDisplacement[3]; // struct _PMD // | +======================================+
7753  __int32 sizeOrOffset; // |
7754  __int32 copyFunction; // | CatchableType:
7755  }; // +---> +====================+
7756  // | ... | std::type_info:
7757 #pragma pack (pop) // | pType (ptr/RVA) ---+------> +==================+
7758  // | ... | |type_info data |
7759 } // namespace Win32 // +====================+ |... |
7760  // +==================+
7761 #endif
7762 
7763 // Similar to __CxxDetectRethrow(), see C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\crtsrc\vcruntime\frame.cpp:
7764 
7765 #define _TX_MSC__CXX_DETECT_RETHROW( exc ) \
7766  ( \
7767  (exc) && \
7768  (exc) -> ExceptionCode == EXCEPTION_CPP_MSC && \
7769  (exc) -> NumberParameters >= 3 && \
7770  \
7771  ((exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || \
7772  (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || \
7773  (exc)-> ExceptionInformation[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3) && \
7774  \
7775  (exc) -> ExceptionInformation[2] == 0 \
7776  )
7777 
7778 #endif // TX_COMPILED
7779 
7780 //}
7781 //-----------------------------------------------------------------------------------------------------------------
7782 
7783 //-----------------------------------------------------------------------------------------------------------------
7784 //{ The corresponding structures for GCC
7785 //
7786 // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h
7787 // See: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi
7788 //-----------------------------------------------------------------------------------------------------------------
7789 
7790 #if defined (_GCC_VER)
7791 
7792 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
7793 
7794  // GCC ABI C++ Exception layout. A/B are ExceptionInformation[0].
7795 namespace ABI { // --------------------------------------------------------------
7796  //
7797 struct __cxa_exception // Case A: "_Unwind_Exception* A" is undependent exception:
7798  { // --------------------------------------------------------
7799  union { //
7800  struct // __cxa_exception: std::type_info:
7801  { // -*--+====================+ +==================+
7802  ::std::type_info* exceptionType; // ^ |exceptionType* -----+---->|type_info data |
7803  void (*exceptionDestructor)(void*); // | |... | |... |
7804  }; // -1 | | +==================+
7805  struct // | | |
7806  { // A >----|--+--------------------+
7807  __cxa_exception* primaryException; // | | |unwindHeader |
7808  void (*padding)(); // +1 | | |
7809  }; // | | | |
7810  }; // V | | |
7811  // -*--- +====================+
7812  void (*unexpected_handler)(); // |object |
7813  std::terminate_handler terminateHandler; // +--------------------+
7814  //
7815  __cxa_exception* nextException; // Case B: "_Unwind_Exception* B" is dependent exception
7816  int handlerCount; // (unwindHeader.exception_class & 1 != 0):
7817  int handlerSwitchValue; // -----------------------------------------------------
7818  const unsigned char* actionRecord; //
7819  const unsigned char* languageSpecificData; // __cxa_exception: __cxa_exception:
7820  void* catchTemp; // -*--+====================+ -*--+=================+
7821  void* adjustedPtr; // ^ |primaryException* --+-- ^ |exceptionType* |
7822  // | |... | \ | |... |
7823  _Unwind_Exception unwindHeader; // -1 | | | | | |
7824  }; // | | | | | | |
7825  // B >----|--+--------------------+ | -1 +-----------------+
7826 struct __cxa_eh_globals // | | |unwindHeader | | | |unwindHeader |
7827  { // +1 | | | | | | |
7828  __cxa_exception* caughtExceptions; // | | | | | | | |
7829  unsigned int uncaughtExceptions; // V | | | \ | | |
7830  }; // -*--- +====================+ -->*--+=================+
7831  // |... | |object |
7832 } // namespace ABI // . . | |
7833  // +-----------------+
7834 
7835 extern "C" ABI::__cxa_eh_globals* __cxa_get_globals();
7836 
7837 #endif // TX_COMPILED
7838 
7839 #endif
7840 
7841 //}
7842 //-----------------------------------------------------------------------------------------------------------------
7843 
7844 //-----------------------------------------------------------------------------------------------------------------
7845 //{ Hand-made IAT.
7846 // Some IDEs don't link with these libs by default in console projects, so do sunrise by hand. :(
7847 //-----------------------------------------------------------------------------------------------------------------
7848 
7849 // Hand-made DLLIMPORT helpers
7850 
7851 #define _TX_DLLIMPORT( lib, retval, name, params ) TX_DLLIMPORT (true, lib ".dll", retval, name, params, WINAPI)
7852 #define _TX_DLLIMPORT_OPT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, WINAPI)
7853 #define _TX_DLLIMPORT_CRT( lib, retval, name, params ) TX_DLLIMPORT (false, lib ".dll", retval, name, params, please)
7854 
7855 void (*_txDllImport (const char dllFileName[], const char funcName[], bool required = true)) ();
7856 
7857 //-----------------------------------------------------------------------------------------------------------------
7858 
7859 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
7860 
7861 namespace Win32 {
7862 
7863 _TX_DLLIMPORT ("GDI32", HDC, CreateCompatibleDC, (HDC dc));
7864 _TX_DLLIMPORT ("GDI32", HBITMAP, CreateCompatibleBitmap, (HDC dc, int width, int height));
7865 _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetStockObject, (int object));
7866 _TX_DLLIMPORT ("GDI32", HGDIOBJ, SelectObject, (HDC dc, HGDIOBJ object));
7867 _TX_DLLIMPORT ("GDI32", HGDIOBJ, GetCurrentObject, (HDC dc, unsigned objectType));
7868 _TX_DLLIMPORT ("GDI32", int, GetObjectA, (HGDIOBJ obj, int bufsize, void* buffer));
7869 _TX_DLLIMPORT ("GDI32", DWORD, GetObjectType, (HGDIOBJ object));
7870 _TX_DLLIMPORT ("GDI32", bool, DeleteDC, (HDC dc));
7871 _TX_DLLIMPORT ("GDI32", bool, DeleteObject, (HGDIOBJ object));
7872 _TX_DLLIMPORT ("GDI32", COLORREF, SetTextColor, (HDC dc, COLORREF color));
7873 _TX_DLLIMPORT ("GDI32", COLORREF, SetBkColor, (HDC dc, COLORREF color));
7874 _TX_DLLIMPORT ("GDI32", int, SetBkMode, (HDC dc, int bkMode));
7875 _TX_DLLIMPORT ("GDI32", HFONT, CreateFontA, (int height, int width, int escapement, int orientation,
7876  int weight, DWORD italic, DWORD underline, DWORD strikeout,
7877  DWORD charSet, DWORD outputPrec, DWORD clipPrec,
7878  DWORD quality, DWORD pitchAndFamily, const char face[]));
7879 _TX_DLLIMPORT ("GDI32", int, EnumFontFamiliesExA, (HDC dc, LPLOGFONT logFont, FONTENUMPROC enumProc,
7880  LPARAM lParam, DWORD reserved));
7881 _TX_DLLIMPORT ("GDI32", COLORREF, SetPixel, (HDC dc, int x, int y, COLORREF color));
7882 _TX_DLLIMPORT ("GDI32", COLORREF, GetPixel, (HDC dc, int x, int y));
7883 _TX_DLLIMPORT ("GDI32", HPEN, CreatePen, (int penStyle, int width, COLORREF color));
7884 _TX_DLLIMPORT ("GDI32", HBRUSH, CreateSolidBrush, (COLORREF color));
7885 _TX_DLLIMPORT ("GDI32", bool, MoveToEx, (HDC dc, int x, int y, POINT* point));
7886 _TX_DLLIMPORT ("GDI32", bool, LineTo, (HDC dc, int x, int y));
7887 _TX_DLLIMPORT ("GDI32", bool, Polygon, (HDC dc, const POINT points[], int count));
7888 _TX_DLLIMPORT ("GDI32", bool, Polyline, (HDC dc, const POINT points[], int count));
7889 _TX_DLLIMPORT ("GDI32", bool, PolyBezier, (HDC dc, const POINT points[], int count));
7890 _TX_DLLIMPORT ("GDI32", bool, Rectangle, (HDC dc, int x0, int y0, int x1, int y1));
7891 _TX_DLLIMPORT ("GDI32", bool, RoundRect, (HDC dc, int x0, int y0, int x1, int y1, int sizeX, int sizeY));
7892 _TX_DLLIMPORT ("GDI32", bool, Ellipse, (HDC dc, int x0, int y0, int x1, int y1));
7893 _TX_DLLIMPORT ("GDI32", bool, Arc, (HDC dc, int x0, int y0, int x1, int y1,
7894  int xStart, int yStart, int xEnd, int yEnd));
7895 _TX_DLLIMPORT ("GDI32", bool, Pie, (HDC dc, int x0, int y0, int x1, int y1,
7896  int xStart, int yStart, int xEnd, int yEnd));
7897 _TX_DLLIMPORT ("GDI32", bool, Chord, (HDC dc, int x0, int y0, int x1, int y1,
7898  int xStart, int yStart, int xEnd, int yEnd));
7899 _TX_DLLIMPORT ("GDI32", bool, TextOutA, (HDC dc, int x, int y, const char string[], int length));
7900 _TX_DLLIMPORT ("GDI32", UINT, SetTextAlign, (HDC dc, unsigned mode));
7901 _TX_DLLIMPORT ("GDI32", bool, GetTextExtentPoint32A, (HDC dc, const char string[], int length, SIZE* size));
7902 _TX_DLLIMPORT ("GDI32", bool, ExtFloodFill, (HDC dc, int x, int y, COLORREF color, unsigned type));
7903 _TX_DLLIMPORT ("GDI32", bool, BitBlt, (HDC dest, int xDest, int yDest, int width, int height,
7904  HDC src, int xSrc, int ySrc, DWORD rOp));
7905 _TX_DLLIMPORT ("GDI32", bool, StretchBlt, (HDC dest, int xDest, int yDest, int width, int height,
7906  HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp));
7907 _TX_DLLIMPORT ("GDI32", bool, PlgBlt, (HDC dest, const POINT* parallelogram,
7908  HDC src, int xSrc, int ySrc, int width, int height,
7909  HBITMAP mask, int xMask, int yMask));
7910 _TX_DLLIMPORT ("GDI32", int, SetDIBitsToDevice, (HDC dc, int xDest, int yDest, DWORD width, DWORD height,
7911  int xSrc, int ySrc, unsigned startLine, unsigned numLines,
7912  const void* data, const BITMAPINFO* info, unsigned colorUse));
7913 _TX_DLLIMPORT ("GDI32", int, GetDIBits, (HDC hdc, HBITMAP hbmp, unsigned uStartScan, unsigned cScanLines,
7914  void* lpvBits, BITMAPINFO* lpbi, unsigned usage));
7915 _TX_DLLIMPORT ("GDI32", bool, PatBlt, (HDC dc, int x0, int y0, int width, int height, DWORD rOp));
7916 _TX_DLLIMPORT ("GDI32", int, SetROP2, (HDC dc, int mode));
7917 _TX_DLLIMPORT ("GDI32", int, SetStretchBltMode, (HDC dc, int mode));
7918 _TX_DLLIMPORT ("GDI32", DWORD, GdiSetBatchLimit, (DWORD limit));
7919 _TX_DLLIMPORT ("GDI32", HBITMAP, CreateDIBSection, (HDC dc, const BITMAPINFO* bmInfo, unsigned colorUsage, void **vBits,
7920  HANDLE section, DWORD offset));
7921 
7922 _TX_DLLIMPORT ("User32", int, DrawTextA, (HDC dc, const char text[], int length, RECT* rect, unsigned format));
7923 _TX_DLLIMPORT ("User32", HANDLE, LoadImageA, (HINSTANCE inst, const char name[], unsigned type,
7924  int sizex, int sizey, unsigned mode));
7925 _TX_DLLIMPORT_OPT ("User32", bool, IsHungAppWindow, (HWND wnd));
7926 _TX_DLLIMPORT_OPT ("User32", HWND, GhostWindowFromHungWindow, (HWND wnd));
7927 _TX_DLLIMPORT_OPT ("User32", bool, FlashWindowEx, (const FLASHWINFO* flash));
7928 
7929 _TX_DLLIMPORT ("WinMM", bool, PlaySound, (const char sound[], HMODULE mod, DWORD mode));
7930 
7931 _TX_DLLIMPORT_OPT ("MSImg32", bool, TransparentBlt, (HDC dest, int destX, int destY, int destWidth, int destHeight,
7932  HDC src, int srcX, int srcY, int srcWidth, int srcHeight,
7933  unsigned transparentColor));
7934 _TX_DLLIMPORT_OPT ("MSImg32", bool, AlphaBlend, (HDC dest, int destX, int destY, int destWidth, int destHeight,
7935  HDC src, int srcX, int srcY, int srcWidth, int srcHeight,
7936  BLENDFUNCTION blending));
7937 
7938 _TX_DLLIMPORT ("Kernel32", void, ExitProcess, (unsigned retcode));
7939 _TX_DLLIMPORT ("Kernel32", bool, TerminateProcess, (HANDLE process, unsigned retcode));
7940 _TX_DLLIMPORT_OPT ("Kernel32", void, FatalExit, (int retcode));
7941 _TX_DLLIMPORT_OPT ("Kernel32", void, FatalAppExitA, (unsigned action, const char message[]));
7942 _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetThreadId, (HANDLE thread));
7943 _TX_DLLIMPORT ("Kernel32", HWND, GetConsoleWindow, (void));
7944 _TX_DLLIMPORT_OPT ("Kernel32", bool, SetConsoleFont, (HANDLE con, DWORD fontIndex));
7945 _TX_DLLIMPORT_OPT ("Kernel32", DWORD, GetNumberOfConsoleFonts, (void));
7946 _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFont, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFO* curFont));
7947 _TX_DLLIMPORT_OPT ("Kernel32", bool, GetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont));
7948 _TX_DLLIMPORT_OPT ("Kernel32", bool, SetCurrentConsoleFontEx, (HANDLE con, bool maxWnd, CONSOLE_FONT_INFOEX* curFont));
7949 _TX_DLLIMPORT_OPT ("Kernel32", void, RtlCaptureContext, (CONTEXT* contextRecord));
7950 _TX_DLLIMPORT_OPT ("Kernel32", USHORT, RtlCaptureStackBackTrace, (DWORD framesToSkip, DWORD framesToCapture, void** backTrace, DWORD* hash));
7951 _TX_DLLIMPORT_OPT ("Kernel32", void*, AddVectoredExceptionHandler, (unsigned long firstHandler, PVECTORED_EXCEPTION_HANDLER handler));
7952 _TX_DLLIMPORT_OPT ("Kernel32", unsigned, RemoveVectoredExceptionHandler,(void* handler));
7953 _TX_DLLIMPORT_OPT ("Kernel32", bool, GetModuleHandleEx, (DWORD flags, const char moduleName[], HMODULE* module));
7954 _TX_DLLIMPORT_OPT ("Kernel32", bool, IsWow64Process, (HANDLE process, int* isWow64Process));
7955 _TX_DLLIMPORT_OPT ("Kernel32", bool, Wow64GetThreadContext, (HANDLE thread, WOW64_CONTEXT* context));
7956 _TX_DLLIMPORT_OPT ("Kernel32", bool, SetThreadStackGuarantee, (unsigned long* stackSize));
7957 
7958 _TX_DLLIMPORT ("OLE32", HRESULT, CoInitialize, (void*));
7959 _TX_DLLIMPORT ("OLE32", HRESULT, CoCreateInstance, (REFCLSID clsId, IUnknown*, DWORD, REFIID iId, void** value));
7960 _TX_DLLIMPORT ("OLE32", void, CoUninitialize, (void));
7961 
7962 _TX_DLLIMPORT ("Shell32", HINSTANCE,ShellExecuteA, (HWND wnd, const char operation[], const char file[],
7963  const char parameters[], const char directory[], int showCmd));
7964 
7965 _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIA, (const char string[], const char search[]));
7966 _TX_DLLIMPORT ("ShlWAPI", char*, StrStrIW, (const wchar_t string[], const wchar_t search[]));
7967 
7968 _TX_DLLIMPORT_OPT ("NTDLL", char*, wine_get_version, (void));
7969 _TX_DLLIMPORT ("NTDLL", NTSTATUS, NtQueryInformationProcess, (HANDLE process, int infoClass,
7970  void* processInfo, unsigned long szProcessInfo, unsigned long* szReturnInfo));
7971 
7972 _TX_DLLIMPORT_CRT ("MSVCRT", void, exit, (int retcode));
7973 _TX_DLLIMPORT_CRT ("MSVCRT", void, _cexit, (void));
7974 _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _fpreset, (void));
7975 _TX_DLLIMPORT_CRT ("MSVCRT", unsigned, _controlfp, (unsigned control, unsigned mask));
7976 _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthread, (void (__cdecl* start_address) (void*), unsigned stack_size, void* arglist));
7977 _TX_DLLIMPORT_CRT ("MSVCRT", uintptr_t,_beginthreadex, (void* security, unsigned stack_size, unsigned (__stdcall* start_address) (void*),
7978  void *arglist, unsigned init_flag, unsigned* thread_addr));
7979 _TX_DLLIMPORT_CRT ("MSVCRT", char*, __unDName, (char* outStr, const char* mangledName, int outStrLen,
7980  void* (*mallocFunc) (size_t size), void (*freeFunc) (void *pointer),
7981  unsigned short flags));
7982 _TX_DLLIMPORT_CRT ("MSVCRT", unexpected_handler, set_unexpected, (unexpected_handler handler));
7983 
7984 _TX_DLLIMPORT_OPT ("OpenGL32", HDC, wglGetCurrentDC, (void));
7985 _TX_DLLIMPORT_OPT ("OpenGL32", unsigned, glGetError, (void));
7986 _TX_DLLIMPORT_OPT ("Glu32", const char*, gluErrorString, (unsigned error));
7987 
7988 _TX_DLLIMPORT_OPT ("ComDlg32", DWORD, CommDlgExtendedError, (void));
7989 
7990 _TX_DLLIMPORT_OPT ("DbgHelp*", bool, MiniDumpWriteDump, (HANDLE process, DWORD processId, HANDLE file, MINIDUMP_TYPE dumpType,
7991  MINIDUMP_EXCEPTION_INFORMATION* exceptionParam,
7992  MINIDUMP_USER_STREAM_INFORMATION* userStreamParam,
7993  MINIDUMP_CALLBACK_INFORMATION* callbackParam));
7994 
7995 _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD, SymSetOptions, (DWORD options));
7996 _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess));
7997 _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol));
7998 _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line));
7999 _TX_DLLIMPORT_OPT ("DbgHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr));
8000 _TX_DLLIMPORT_OPT ("DbgHelp*", bool, SymCleanup, (HANDLE process));
8001 _TX_DLLIMPORT_OPT ("DbgHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase));
8002 _TX_DLLIMPORT_OPT ("DbgHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord,
8003  PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc,
8004  PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc,
8005  PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc,
8006  PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc));
8007 namespace MinGW {
8008 _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD, SymSetOptions, (DWORD options));
8009 _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymInitialize, (HANDLE process, const char userSearchPath[], bool invadeProcess));
8010 _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymFromAddr, (HANDLE process, DWORD64 addr, DWORD64* offset, SYMBOL_INFO* symbol));
8011 _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymGetLineFromAddr64, (HANDLE process, DWORD64 addr, DWORD* offset, IMAGEHLP_LINE64* line));
8012 _TX_DLLIMPORT_OPT ("MgwHelp*", DWORD64, SymGetModuleBase64, (HANDLE process, DWORD64 addr));
8013 _TX_DLLIMPORT_OPT ("MgwHelp*", bool, SymCleanup, (HANDLE process));
8014 _TX_DLLIMPORT_OPT ("MgwHelp*", void*, SymFunctionTableAccess64, (HANDLE process, DWORD64 addrBase));
8015 _TX_DLLIMPORT_OPT ("MgwHelp*", bool, StackWalk64, (DWORD arch, HANDLE process, HANDLE thread, STACKFRAME64* frame, void* ctxRecord,
8016  PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryFunc,
8017  PFUNCTION_TABLE_ACCESS_ROUTINE64 tableAccessFunc,
8018  PGET_MODULE_BASE_ROUTINE64 getModuleBaseFunc,
8019  PTRANSLATE_ADDRESS_ROUTINE64 translateAddressFunc));
8020 } // namespace MinGW
8021 } // namespace Win32
8022 
8023 #endif // TX_COMPILED
8024 
8025 //}
8026 //-----------------------------------------------------------------------------------------------------------------
8027 
8029 //}
8030 //=================================================================================================================
8031 
8032 //=================================================================================================================
8033 //{ Internal function prototypes, macros and constants
8034 // @name Прототипы внутренних функций, макросы и константы//================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize(); void _txCleanup(); HWND _txCanvas_CreateWindow (const SIZE* size); bool _txCanvas_OnCREATE (HWND wnd); bool _txCanvas_OnDESTROY (HWND wnd); bool _txCanvas_OnCLOSE (HWND); bool _txCanvas_OnPAINT (HWND wnd); bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down); bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info); bool _txCanvas_OnTIMER (HWND wnd, WPARAM id); bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords); bool _txCanvas_OnMOUSELEAVE (HWND wnd); bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar); bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd); bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd); unsigned WINAPI _txCanvas_ThreadProc (void* data); LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL, RGBQUAD** pixels = NULL) tx_nodiscard; bool _txBuffer_Delete (HDC* dc); bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC()); HWND _txConsole_Attach(); bool _txConsole_OK() tx_nodiscard; bool _txConsole_Detach (bool activate); bool _txConsole_Draw (HDC dc); bool _txConsole_SetUnicodeFont(); const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra); HWND txCreateExtraWindow (CREATESTRUCT createData); HICON _txCreateTXIcon (int size) tx_nodiscard; int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL, int checkOfs = 0, const wchar_t checkLetters[2] = NULL); int _txPauseBeforeTermination (HWND canvas); int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard; void _txActivateWindow (HWND wnd, unsigned mode); int _txGetInput(); LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar); const char* _txPlayVideo_FindVLC() tx_nodiscard; bool _txCreateShortcut (const char shortcutName[], const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL, const char description[] = NULL, int cmdShow = SW_SHOWNORMAL, const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0, COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD)); void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) tx_nodiscard; void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]); const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args); void _txOnTerminate(); void _txOnUnexpected(); void _txOnPureCall(); void _txOnNewHandlerAnsi(); int _txOnNewHandler (size_t size); void _txOnSignal (int signal = 0, int fpe = 0); BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type); void _txOnSecurityError (int code, void*); void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code); int _txOnMatherr (_exception* except); void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned line, uintptr_t); int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line); int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5); int _txOnErrorReport (int type, const char* text, int* ret); int tx_glGetError (int setError = INT_MIN); void _txOnCExit(); void _txOnExit (int retcode); void _txOnFatalExit (int retcode); void _txOnExitProcess (unsigned retcode); void _txOnFatalAppExitA (unsigned action, const char message[]); bool _txOnTerminateProcess (HANDLE process, unsigned retcode); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter); void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc); long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc); long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]); intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]); intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type); intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0, unsigned params = 0, const ULONG_PTR info[] = NULL); void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?", bool readSource = true); const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true, CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread()); int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL, HANDLE thread = GetCurrentThread()); const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false); const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2); bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL, Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL, const char** source = NULL, int context = 2); intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN); bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL); uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL, int useHotPatching = false, HMODULE module = NULL, bool debug = false); bool _txInDll() tx_nodiscard; PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard; bool _txKillProcess (DWORD pid); int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/); bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true); bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid()); IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard; bool _txIsConsoleSubsystem(); const char* _txAppInfo() tx_nodiscard; #if defined (_CLANG_VER) && !defined (_MSC_VER) void _txLibCppDebugFunction (std::__libcpp_debug_info const& info); #endif #endif // TX_COMPILED inline bool _txCanvas_OK () tx_nodiscard; int _txCanvas_SetRefreshLock (int count); const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0, const char msg[] = NULL, ...) tx_printfy (5); bool _txIsBadReadPtr (const void* address); intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3); intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg); bool _txIsTTY (int fd); void txReopenStdio(); #if defined (__CYGWIN__) int _getch(); int _putch (int ch); int _kbhit() tx_nodiscard; #endif //----------------------------------------------------------------------------------------------------------------- // There are macros for __FILE__ and __LINE__ to work properly. #if !defined (NDEBUG) #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \ (assert (cond), true) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \ (TX_ERROR ("\a" "Параметр \"%s\" неверен." \ " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка.", #dc), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (TX_ERROR ("\a" "%s" \ "Если вы указали параметр \"%s\", то он неверен.%s", \ (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \ #dc, \ ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \ "или не загрузилась картинка." : "")), 1) ) #else #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \ (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) ) #define _TX_TXWINDOW_FAILED() ( !txOK() && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \ (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) ) #endif //----------------------------------------------------------------------------------------------------------------- // Take action in debug configuration only. // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'( #if !defined (NDEBUG) #define _TX_ON_DEBUG( code ) { code; } #else #define _TX_ON_DEBUG( code ) ; #endif //----------------------------------------------------------------------------------------------------------------- // Invokes an error without location information. "$$" restores TX-related call location context #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__) //----------------------------------------------------------------------------------------------------------------- // Safe call of a function via its pointer #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 ) #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 ) //----------------------------------------------------------------------------------------------------------------- // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x. #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \ !(cond) && GetTickCount() < _t; \ Sleep (_txWindowUpdateInterval)) \ ; \ \ if (!(cond)) \ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); } //----------------------------------------------------------------------------------------------------------------- // Detouring in case of SEH mechanism #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 ) #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; } //----------------------------------------------------------------------------------------------------------------- // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code. #if defined (IN) // #undef IN #endif #if defined (OUT) // #undef OUT #endif //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal global data //! @name Внутренние глобальные данные // // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :) // // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же. // Здесь это сделано только в образовательных целях. // // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс. //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<< const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна _TX_IDM_CONSOLE = 40001, _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas //----------------------------------------------------------------------------------------------------------------- volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize(); volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main() volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT() RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0] HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP), // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock() UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question. int _txConsole = false; // Only first TXLib module in app can own the console bool _txMain = false; // First TXLib wnd opened (closing it terminates program) bool _txIsDll = false; // TXLib module is in DLL volatile bool _txRunning = false; // main() is still running volatile bool _txExit = false; // exit() is active volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE() volatile unsigned _txMouseButtons = 0; volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook(). _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro volatile int _txErrors = 0; // TX_ERROR calls sequental number volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError() volatile long _txSENumber = 0; // SEH exceptions sequental number volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess, (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA, (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp, (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier, (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler, (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace, (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize, (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions, (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64, (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr, (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup, (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64, (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64, (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64, (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext }; volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- extern volatile unsigned _txCanaryFirst; extern volatile unsigned _txCanaryLast; extern volatile HWND _txCanvas_Window; extern volatile unsigned _txCanvas_ThreadId; extern HDC _txCanvas_BackBuf[2]; extern RGBQUAD* _txCanvas_Pixels; extern volatile int _txCanvas_RefreshLock; extern volatile WNDPROC _txAltWndProc; extern volatile bool _txExit; extern volatile int _txOGLError; //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib engine init/check/cleanup //! @name Инициализация/проверка/завершение TXLib //================================================================================================================= //! @{ //----------------------------------------------------------------------------------------------------------------- //{ Early initialization //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< int _txInitialize() { if (_txInitialized) return 1; _txInitialized = 1; #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585 #endif #if defined (_TX_ALLOW_TRACE) _txLocLvlSet (1); #endif _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" " "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n"); OutputDebugString ("\n")); _txMainThreadId = GetCurrentThreadId(); _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId); $3 _txIsDll = _txInDll(); $ if (!_txIsDll) { $ _txConsole = ! FindAtom ("_txConsole"); $ (void) AddAtom ("_txConsole"); //-V530 } $ if (_txConsole) { $ _txCheckSourceCP (_TX_CODEPAGE, true); $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ _txOnSignal(); $ if (!*_txLogName) {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); } $ if (!_txIsDll) { $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler)); $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter); } $ ::std::set_terminate (_txOnTerminate); $ ::std::set_new_handler (_txOnNewHandlerAnsi); $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected)); #if defined (_CLANG_VER) && !defined (_MSC_VER) $ ::std::__libcpp_debug_function = _txLibCppDebugFunction; #endif $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true); $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #if defined (_MSC_VER) $ _set_printf_count_output (1); $ _set_new_handler (_txOnNewHandler); $ _set_new_mode (1); #if !defined (_CLANG_VER) $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); $ _CrtSetAllocHook (_txOnAllocHook); $ unsigned mode = _CRTDBG_MODE_FILE; $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0; $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode); $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW); $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG); $ _set_abort_behavior (0, _CALL_REPORTFAULT); $ _RTC_SetErrorFunc (_txOnRTCFailure); $ _set_purecall_handler (_txOnPureCall); $ _set_invalid_parameter_handler (_txOnInvalidParam); #endif #if defined (__STDC_LIB_EXT1__) $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi); #endif #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386) $ __setusermatherr (_txOnMatherr); #endif #if !defined (__CYGWIN__) $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR); #endif $ HWND console = _txConsole_Attach(); $ SetWindowTextA (console, txGetModuleFileName (false)); } $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL"); $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL"); $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL"); $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit); $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit); $ InitializeCriticalSection (&_txCanvas_LockBackBuf); $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted; $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted; $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted; $ Win32::DeleteDC (dc) asserted; $ atexit (_txCleanup); $ if (_txConsole) { $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ tx_fpreset(); $ srand ((unsigned) time (NULL)); //-V202 $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif } $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used" $ return 1; } //----------------------------------------------------------------------------------------------------------------- bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/) { $3 const char* sCodePage = NULL; $ int codePage = 0; $ switch (((unsigned const char*) "А") [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
8035 //=================================================================================================================
8037 
8038 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
8039 
8040 int _txInitialize();
8041 void _txCleanup();
8042 
8043 HWND _txCanvas_CreateWindow (const SIZE* size);
8044 
8045 bool _txCanvas_OnCREATE (HWND wnd);
8046 bool _txCanvas_OnDESTROY (HWND wnd);
8047 bool _txCanvas_OnCLOSE (HWND);
8048 bool _txCanvas_OnPAINT (HWND wnd);
8049 bool _txCanvas_OnKEY (HWND wnd, WPARAM vk, LPARAM info, bool down);
8050 bool _txCanvas_OnCHAR (HWND wnd, WPARAM ch, LPARAM info);
8051 bool _txCanvas_OnTIMER (HWND wnd, WPARAM id);
8052 bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords);
8053 bool _txCanvas_OnMOUSELEAVE (HWND wnd);
8054 bool _txCanvas_OnCREATEWND (HWND wnd, WPARAM, LPARAM lpar);
8055 bool _txCanvas_OnDESTROYWND (HWND wnd, WPARAM, LPARAM lpar);
8056 bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd);
8057 bool _txCanvas_OnCmdABOUT (HWND wnd, WPARAM cmd);
8058 
8059 unsigned WINAPI _txCanvas_ThreadProc (void* data);
8060 LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar);
8061 
8062 HDC _txBuffer_Create (HWND wnd = NULL, const POINT* size = NULL, HBITMAP bitmap = NULL,
8063  RGBQUAD** pixels = NULL) tx_nodiscard;
8064 bool _txBuffer_Delete (HDC* dc);
8065 bool _txBuffer_Select (HGDIOBJ obj, HDC dc = txDC());
8066 
8067 HWND _txConsole_Attach();
8068 bool _txConsole_OK() tx_nodiscard;
8069 bool _txConsole_Detach (bool activate);
8070 bool _txConsole_Draw (HDC dc);
8071 bool _txConsole_SetUnicodeFont();
8072 
8073 const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra);
8074 HWND txCreateExtraWindow (CREATESTRUCT createData);
8075 HICON _txCreateTXIcon (int size) tx_nodiscard;
8076 int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng = NULL,
8077  int checkOfs = 0, const wchar_t checkLetters[2] = NULL);
8078 int _txPauseBeforeTermination (HWND canvas);
8079 int _txIsParentWaitable (DWORD* parentPID = NULL) tx_nodiscard;
8080 void _txActivateWindow (HWND wnd, unsigned mode);
8081 int _txGetInput();
8082 
8083 LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar);
8084 const char* _txPlayVideo_FindVLC() tx_nodiscard;
8085 
8086 bool _txCreateShortcut (const char shortcutName[],
8087  const char fileToLink[], const char args[] = NULL, const char workDir[] = NULL,
8088  const char description[] = NULL, int cmdShow = SW_SHOWNORMAL,
8089  const char iconFile[] = NULL, int iconIndex = 0, int fontSize = 0,
8090  COORD bufSize = ZERO (COORD), COORD wndSize = ZERO (COORD), COORD wndOrg = ZERO (COORD));
8091 
8092 void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle,
8093  WORD controls, short x, short y, short cx, short cy,
8094  const char caption[], const char font[], WORD fontsize,
8095  const char menu[]) tx_nodiscard;
8096 
8097 void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle,
8098  short x, short y, short cx, short cy,
8099  WORD id, const char wclass[], const char caption[]);
8100 
8101 const char* _txProcessError (const char file[], int line, const char func[], unsigned color,
8102  const char msg[], va_list args);
8103 void _txOnTerminate();
8104 void _txOnUnexpected();
8105 void _txOnPureCall();
8106 void _txOnNewHandlerAnsi();
8107 int _txOnNewHandler (size_t size);
8108 void _txOnSignal (int signal = 0, int fpe = 0);
8109 BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type);
8110 void _txOnSecurityError (int code, void*);
8111 void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code);
8112 int _txOnMatherr (_exception* except);
8113 void _txOnInvalidParam (const wchar_t* expr, const wchar_t* func, const wchar_t* file,
8114  unsigned line, uintptr_t);
8115 int _txOnAllocHook (int type, void* data, size_t size, int use, long request,
8116  const unsigned char* file, int line);
8117 int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...) tx_printfy (5);
8118 int _txOnErrorReport (int type, const char* text, int* ret);
8119 int tx_glGetError (int setError = INT_MIN);
8120 
8121 void _txOnCExit();
8122 void _txOnExit (int retcode);
8123 void _txOnFatalExit (int retcode);
8124 void _txOnExitProcess (unsigned retcode);
8125 void _txOnFatalAppExitA (unsigned action, const char message[]);
8126 bool _txOnTerminateProcess (HANDLE process, unsigned retcode);
8127 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI
8128  _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter);
8129 void _txWatchdogTerminator (void* timeout); // Only Arnold-type series are supported, not T1000
8130 
8131 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc);
8132 long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc);
8133 long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[]);
8134 intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]);
8135 intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type);
8136 intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code = 0,
8137  unsigned params = 0, const ULONG_PTR info[] = NULL);
8138 
8139 void _txStackBackTrace (const char file[] = "?", int line = 0, const char func[] = "?",
8140  bool readSource = true);
8141 const char* _txCaptureStackBackTrace (int framesToSkip = 0, bool readSource = true,
8142  CONTEXT* context = NULL, EXCEPTION_POINTERS* exc = NULL, HANDLE thread = GetCurrentThread());
8143 int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context = NULL,
8144  HANDLE thread = GetCurrentThread());
8145 const char* _txCaptureStackBackTraceTX (int framesToSkip = 0, bool readSource = false);
8146 
8147 const char* _txSymPrintFromAddr (void* addr = NULL, const char format[] = NULL, ...) tx_printfy (2);
8148 bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol = NULL,
8149  Win32::IMAGEHLP_LINE64** line = NULL, const char** module = NULL,
8150  const char** source = NULL, int context = 2);
8151 intptr_t _txReadSource (char buf[], intptr_t size, const char file[],
8152  int linStart = 0, int linEnd = INT_MIN, int linMark = INT_MIN);
8153 bool _txCreateMiniDump (EXCEPTION_POINTERS* exc = NULL);
8154 
8155 uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] = NULL,
8156  int useHotPatching = false, HMODULE module = NULL, bool debug = false);
8157 bool _txInDll() tx_nodiscard;
8158 PROCESSENTRY32* _txFindProcess (unsigned pid = GetCurrentProcessId()) tx_nodiscard;
8159 bool _txKillProcess (DWORD pid);
8160 int _txTaskKill (const char name[] /*= NULL*/, const char cmdLineSubstr[] /*= NULL*/, unsigned pid /*= 0*/);
8161 bool _txCheckSourceCP (int needCP = _TX_CODEPAGE, bool verbose = true);
8162 bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid = _getpid());
8163 IMAGE_NT_HEADERS*_txGetNtHeaders (HMODULE module = GetModuleHandle (NULL)) tx_nodiscard;
8164 bool _txIsConsoleSubsystem();
8165 const char* _txAppInfo() tx_nodiscard;
8166 
8167 #if defined (_CLANG_VER) && !defined (_MSC_VER)
8168 void _txLibCppDebugFunction (std::__libcpp_debug_info const& info);
8169 #endif
8170 
8171 #endif // TX_COMPILED
8172 
8173 inline bool _txCanvas_OK () tx_nodiscard;
8174 int _txCanvas_SetRefreshLock (int count);
8175 
8176 const char* _txError (const char file[] = NULL, int line = 0, const char func[] = NULL, unsigned color = 0,
8177  const char msg[] = NULL, ...) tx_printfy (5);
8178 
8179 bool _txIsBadReadPtr (const void* address);
8180 
8181 intptr_t _tx_snprintf_s (char stream[], intptr_t size, const char format[], ...) tx_printfy (3);
8182 intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg);
8183 bool _txIsTTY (int fd);
8184 void txReopenStdio();
8185 
8186 #if defined (__CYGWIN__)
8187 
8188 int _getch();
8189 int _putch (int ch);
8190 int _kbhit() tx_nodiscard;
8191 
8192 #endif
8193 
8194 //-----------------------------------------------------------------------------------------------------------------
8195 // There are macros for __FILE__ and __LINE__ to work properly.
8196 
8197 #if !defined (NDEBUG)
8198 
8199  #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \
8200  (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) && \
8201  (assert (cond), true) )
8202 
8203  #define _TX_TXWINDOW_FAILED() ( !txOK() && \
8204  (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \
8205  (TX_ERROR ("\a" "Возможно, окно рисования не создано или не в порядке."), 1) )
8206 
8207  #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \
8208  (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) && \
8209  (TX_ERROR ("\a" "Параметр \"%s\" неверен." \
8210  " Возможно, этот холст не создан, или уже уничтожен, " \
8211  "или не загрузилась картинка.", #dc), 1) )
8212  #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \
8213  (TX_ERROR ("\a" "%s" \
8214  "Если вы указали параметр \"%s\", то он неверен.%s", \
8215  (!txWindow()? "Окно рисования не создано или не в порядке.\n" : ""), \
8216  #dc, \
8217  ( txWindow()? " Возможно, этот холст не создан, или уже уничтожен, " \
8218  "или не загрузилась картинка." : "")), 1) )
8219 #else
8220 
8221  #define _TX_ARGUMENT_FAILED( cond ) ( !(cond) && \
8222  (SetLastErrorEx (ERROR_BAD_ARGUMENTS, 0), 1) )
8223 
8224  #define _TX_TXWINDOW_FAILED() ( !txOK() && \
8225  (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) )
8226 
8227  #define _TX_HDC_FAILED( dc ) ( !Win32::GetObjectType (dc) && \
8228  (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) )
8229 
8230  #define _TX_DEFAULT_HDC_FAILED( dc ) ( !(dc) && \
8231  (SetLastErrorEx (ERROR_INVALID_DATA, 0), 1) )
8232 #endif
8233 
8234 //-----------------------------------------------------------------------------------------------------------------
8235 // Take action in debug configuration only.
8236 // Definition ({ expr; }) would be better, but MSVC rejects it. So sad. :'(
8237 
8238 #if !defined (NDEBUG)
8239  #define _TX_ON_DEBUG( code ) { code; }
8240 #else
8241  #define _TX_ON_DEBUG( code ) ;
8242 #endif
8243 
8244 //-----------------------------------------------------------------------------------------------------------------
8245 // Invokes an error without location information. "$$" restores TX-related call location context
8246 
8247 #define _TX_UNEXPECTED( ... ) $$ _txError (NULL, 0, NULL, 0, ##__VA_ARGS__)
8248 
8249 //-----------------------------------------------------------------------------------------------------------------
8250 // Safe call of a function via its pointer
8251 
8252 #define _TX_CALL( func, param ) ( (func)? ((func) param) : 0 )
8253 #define _TX_CALLv( func, param ) ( (func)? ((func) param) : (void)0 )
8254 
8255 //-----------------------------------------------------------------------------------------------------------------
8256 // This is a macro because cond is an expression and is not always a function. Lack of lambdas in pre-C++0x.
8257 
8258 #define _txWaitFor( cond, time ) { for (DWORD _t = GetTickCount() + (time); \
8259  !(cond) && GetTickCount() < _t; \
8260  Sleep (_txWindowUpdateInterval)) \
8261  ; \
8262  \
8263  if (!(cond)) \
8264  _txTrace (__FILE__, __LINE__, NULL, "WARNING: Timeout: " #cond "."); }
8265 
8266 //-----------------------------------------------------------------------------------------------------------------
8267 // Detouring in case of SEH mechanism
8268 
8269 #define _txSetJmp() ( setjmp (_txDumpExceptionObjJmp) == 0 )
8270 
8271 #define _txClearJmp() { *(unsigned long long*) _txDumpExceptionObjJmp = 0; }
8272 
8273 //-----------------------------------------------------------------------------------------------------------------
8274 // IN and OUT are defined in WinDef.h to support Microsoft SAL. Remove them because they are often confused with user's code.
8275 
8276 #if defined (IN)
8277 // #undef IN
8278 #endif
8279 
8280 #if defined (OUT)
8281 // #undef OUT
8282 #endif
8283 
8285 //}
8286 //=================================================================================================================
8287 
8288 //=================================================================================================================
8289 //{ Internal global data
8291 //
8292 // Данные не упакованы в структуру или класс, для того, чтобы это сделали Вы сами :)
8293 //
8294 // Если вы пишете свою библиотеку и используете TXLib.h как пример, не следуйте ему и не делайте так же.
8295 // Здесь это сделано только в образовательных целях.
8296 //
8297 // Будьте практичнее, сделайте структуру и глобальную функцию для доступа к ней, или класс.
8298 //=================================================================================================================
8300 
8301 #ifndef TX_COMPILED // <<<<<<< THE CODE IS HERE, UNFOLD IT <<<
8302 
8303 const int _TX_IDM_ABOUT = 40000, // Идентификаторы системного меню окна
8304  _TX_IDM_CONSOLE = 40001,
8305  _TX_WM_CREATEWND = 0x7FF0, // Сообщения для создания/уничтожения
8306  _TX_WM_DESTROYWND = 0x7FF1; // окон в потоке Canvas
8307 
8308 //-----------------------------------------------------------------------------------------------------------------
8309 
8310 volatile unsigned _txCanaryFirst = 0x776F656D; // A very system value
8311 
8312 int _txInitialized = (_TX_NOINIT +0)? 0 : _txInitialize();
8313 
8314 volatile unsigned _txMainThreadId = 0; // ID потока, где выполняется main()
8315 volatile HANDLE _txMainThread = NULL; // Дексриптор этого потока
8316 
8317 volatile unsigned _txCanvas_ThreadId = 0; // ID потока, владеющего окном холста TXLib
8318 volatile HANDLE _txCanvas_Thread = NULL; // Дексриптор этого потока
8319 volatile HWND _txCanvas_Window = NULL; // Дескриптор окна холста TXLib
8320 
8321 HDC _txCanvas_BackBuf[2] = {NULL, // [0] Main TXLib in-memory DC, where user's pictures lies
8322  NULL}; // [1] Image ready for auto-refresh, see txCanvas_OnPAINT()
8323 
8324 RGBQUAD* _txCanvas_Pixels = NULL; // Memory buffer of _txCanvas_BackBuf[0]
8325 
8326 HBITMAP _txStockBitmap = NULL; // Equivalent of GetStockObject (BITMAP),
8327  // see https://devblogs.microsoft.com/oldnewthing/20100416-00/?p=14313
8328 
8329 CRITICAL_SECTION _txCanvas_LockBackBuf = {0,-1}; // Prevent simultaneous access to back buffer, see txLock()
8330 
8331 UINT_PTR _txCanvas_RefreshTimer = 1; // Timer ID to redraw TXLib window
8332 volatile int _txCanvas_RefreshLock = 0; // Blocks auto on-timer canvas update, see txBegin/txEnd
8333 
8334 ::std::vector<HDC>* _txCanvas_UserDCs = NULL; // List of DCs allocated, for auto-free
8335 
8336 volatile bool _txConsole_IsBlinking = true; // To blink or not to blink, that is the question.
8337 
8338 int _txConsole = false; // Only first TXLib module in app can own the console
8339 bool _txMain = false; // First TXLib wnd opened (closing it terminates program)
8340 bool _txIsDll = false; // TXLib module is in DLL
8341 volatile bool _txRunning = false; // main() is still running
8342 volatile bool _txExit = false; // exit() is active
8343 
8344 volatile POINT _txMousePos = {-1,-1}; // Ask Captn Obviouos about it. See txCanvas_OnMOUSE()
8345 volatile unsigned _txMouseButtons = 0;
8346 
8347 volatile WNDPROC _txAltWndProc = NULL; // Альтернативная оконная функция. См. txSetWindowsHook().
8348 
8349 _tx_thread _txLoc _txLoc::Cur = {}; // Execution point tracking and trace state, see "$" macro
8350 
8351 volatile int _txErrors = 0; // TX_ERROR calls sequental number
8352 volatile int _txOGLError = 0; // Last OpenGL error when using tx_glGetError()
8353 volatile long _txSENumber = 0; // SEH exceptions sequental number
8354 volatile long _txSEFatalNumber = 0; // SEH fatal exceptions sequental number
8355 char _txDumpSE [_TX_BUFSIZE] = ""; // SEH dump data area
8356 char _txTraceSE[_TX_HUGEBUFSIZE] = ""; // Stack trace data area
8357 
8358 LPTOP_LEVEL_EXCEPTION_FILTER _txPrevUEFilter = NULL; // Previous UnhandledExceptionFilter
8359 
8360 jmp_buf _txDumpExceptionObjJmp = {}; // Hook for _txDumpExceptionObj
8361 
8362 const volatile uintptr_t _txForceImport[] = { (uintptr_t) ::TerminateProcess, (uintptr_t) ::ExitProcess,
8363  (uintptr_t) ::FatalExit, (uintptr_t) ::FatalAppExitA,
8364  (uintptr_t) ::exit, (uintptr_t) Win32::_controlfp,
8365  (uintptr_t) Win32::Polyline, (uintptr_t) Win32::PolyBezier,
8366  (uintptr_t) Win32::RoundRect, (uintptr_t) Win32::RemoveVectoredExceptionHandler,
8367  (uintptr_t) Win32::PlgBlt, (uintptr_t) Win32::RtlCaptureStackBackTrace,
8368  (uintptr_t) Win32::SymInitialize, (uintptr_t) Win32::MinGW::SymInitialize,
8369  (uintptr_t) Win32::SymSetOptions, (uintptr_t) Win32::MinGW::SymSetOptions,
8370  (uintptr_t) Win32::SymGetLineFromAddr64, (uintptr_t) Win32::MinGW::SymGetLineFromAddr64,
8371  (uintptr_t) Win32::SymFromAddr, (uintptr_t) Win32::MinGW::SymFromAddr,
8372  (uintptr_t) Win32::SymCleanup, (uintptr_t) Win32::MinGW::SymCleanup,
8373  (uintptr_t) Win32::SymGetModuleBase64, (uintptr_t) Win32::MinGW::SymGetModuleBase64,
8374  (uintptr_t) Win32::SymFunctionTableAccess64, (uintptr_t) Win32::MinGW::SymFunctionTableAccess64,
8375  (uintptr_t) Win32::StackWalk64, (uintptr_t) Win32::MinGW::StackWalk64,
8376  (uintptr_t) Win32::StrStrIA, (uintptr_t) Win32::Wow64GetThreadContext };
8377 
8378 volatile unsigned _txCanaryLast = 0x5E2E2E5E; // Another very system value
8379 
8380 #endif // TX_COMPILED
8381 
8382 //-----------------------------------------------------------------------------------------------------------------
8383 
8384 extern volatile unsigned _txCanaryFirst;
8385 extern volatile unsigned _txCanaryLast;
8386 extern volatile HWND _txCanvas_Window;
8387 extern volatile unsigned _txCanvas_ThreadId;
8388 extern HDC _txCanvas_BackBuf[2];
8389 extern RGBQUAD* _txCanvas_Pixels;
8390 extern volatile int _txCanvas_RefreshLock;
8391 extern volatile WNDPROC _txAltWndProc;
8392 extern volatile bool _txExit;
8393 extern volatile int _txOGLError;
8394 
8396 //}
8397 //=================================================================================================================
8398 
8399 //=================================================================================================================
8400 //{ TXLib engine init/check/cleanup
8402 //=================================================================================================================
8404 
8405 //-----------------------------------------------------------------------------------------------------------------
8406 //{ Early initialization
8407 //-----------------------------------------------------------------------------------------------------------------
8408 
8409 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
8410 
8411 int _txInitialize()
8412  {
8413  if (_txInitialized) return 1;
8414  _txInitialized = 1;
8415 
8416  #if defined (_TX_ALLOC_BREAK) && defined (_MSC_VER) // See http://msdn.microsoft.com/en-us/library/w2fhc9a3%28v=vs.90%29.aspx
8417  _CrtSetBreakAlloc (_TX_ALLOC_BREAK); // and http://support.microsoft.com/ru-ru/kb/151585
8418  #endif
8419 
8420  #if defined (_TX_ALLOW_TRACE)
8421  _txLocLvlSet (1);
8422  #endif
8423 
8424  _TX_ON_DEBUG (OutputDebugString ("\n");
8425  OutputDebugString (_TX_VERSION " - The Dumb Artist Library, " _TX_AUTHOR ": \"" __FILE__ "\" "
8426  "compiled " __DATE__ " " __TIME__ ", " _TX_BUILDMODE " mode, module: " _TX_MODULE "\n");
8427  OutputDebugString ("\n"));
8428 
8429  _txMainThreadId = GetCurrentThreadId();
8430  _txMainThread = OpenThread (THREAD_ALL_ACCESS, false, _txMainThreadId);
8431 
8432 $3 _txIsDll = _txInDll();
8433 
8434 $ if (!_txIsDll)
8435  {
8436 $ _txConsole = ! FindAtom ("_txConsole");
8437 $ (void) AddAtom ("_txConsole"); //-V530
8438  }
8439 
8440 $ if (_txConsole)
8441  {
8442 $ _txCheckSourceCP (_TX_CODEPAGE, true);
8443 
8444 $ unsigned long stackSize = _TX_STACKSIZE;
8445 $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize));
8446 
8447 $ _txOnSignal();
8448 
8449 $ if (!*_txLogName)
8450  {$ _tx_snprintf_s (_txLogName, sizeof (_txLogName) - 1, "%s.log", txGetModuleFileName()); }
8451 
8452 $ if (!_txIsDll)
8453  {
8454 $ _TX_CALL (Win32::AddVectoredExceptionHandler, (1, (PVECTORED_EXCEPTION_HANDLER) _txVectoredExceptionHandler));
8455 $ _txPrevUEFilter = SetUnhandledExceptionFilter ( (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter);
8456  }
8457 
8458 $ ::std::set_terminate (_txOnTerminate);
8459 $ ::std::set_new_handler (_txOnNewHandlerAnsi);
8460 $ _TX_CALL (Win32::set_unexpected, (_txOnUnexpected));
8461 
8462  #if defined (_CLANG_VER) && !defined (_MSC_VER)
8463 $ ::std::__libcpp_debug_function = _txLibCppDebugFunction;
8464  #endif
8465 
8466 $ SetConsoleCtrlHandler (_txOnConsoleCtrlEvent, true);
8467 
8468 $ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
8469 
8470  #if defined (_MSC_VER)
8471 
8472 $ _set_printf_count_output (1);
8473 
8474 $ _set_new_handler (_txOnNewHandler);
8475 $ _set_new_mode (1);
8476 
8477  #if !defined (_CLANG_VER)
8478 
8479 $ _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF);
8480 $ _CrtSetAllocHook (_txOnAllocHook);
8481 
8482 $ unsigned mode = _CRTDBG_MODE_FILE;
8483 $ if (_CrtSetReportHook2 (_CRT_RPTHOOK_INSTALL, (_CRT_REPORT_HOOK) _txOnErrorReport) > 0) mode = 0;
8484 
8485 $ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG | mode);
8486 $ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW);
8487 $ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG | mode | _CRTDBG_MODE_WNDW);
8488 $ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR);
8489 $ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR);
8490 $ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR);
8491 
8492  #endif
8493 
8494 $ _set_abort_behavior (_WRITE_ABORT_MSG, _WRITE_ABORT_MSG);
8495 $ _set_abort_behavior (0, _CALL_REPORTFAULT);
8496 
8497 $ _RTC_SetErrorFunc (_txOnRTCFailure);
8498 $ _set_purecall_handler (_txOnPureCall);
8499 $ _set_invalid_parameter_handler (_txOnInvalidParam);
8500 
8501  #endif
8502 
8503  #if defined (__STDC_LIB_EXT1__)
8504 $ ::std::set_constraint_handler_s (_txOnSecurityErrorAnsi);
8505  #endif
8506 
8507  #if !defined (__CYGWIN__) && defined (_GCC_VER) && (_GCC_VER >= 530) && !defined (i386)
8508 $ __setusermatherr (_txOnMatherr);
8509  #endif
8510 
8511  #if !defined (__CYGWIN__)
8512 $ _set_error_mode (_OUT_TO_MSGBOX | _OUT_TO_STDERR);
8513  #endif
8514 
8515 $ HWND console = _txConsole_Attach();
8516 $ SetWindowTextA (console, txGetModuleFileName (false));
8517  }
8518 
8519 $ _txSetProcAddress ("ExitProcess", (uintptr_t) _txOnExitProcess, "KERNEL32.DLL");
8520 $ _txSetProcAddress ("TerminateProcess", (uintptr_t) _txOnTerminateProcess, "KERNEL32.DLL");
8521 $ _txSetProcAddress ("FatalExit", (uintptr_t) _txOnFatalExit, "KERNEL32.DLL");
8522 $ _txSetProcAddress ("FatalAppExitA", (uintptr_t) _txOnFatalAppExitA, "KERNEL32.DLL");
8523 $ _txSetProcAddress ("UnhandledExceptionFilter", (uintptr_t) _txUnhandledExceptionFilter, "KERNEL32.DLL", true); //-V601
8524 $ _txSetProcAddress ("SetUnhandledExceptionFilter", (uintptr_t) _txOnSetUnhandledExceptionFilter, "KERNEL32.DLL");
8525 $ _txSetProcAddress ("exit", (uintptr_t) _txOnExit);
8526 $ _txSetProcAddress ("_cexit", (uintptr_t) _txOnCExit);
8527 
8528 $ InitializeCriticalSection (&_txCanvas_LockBackBuf);
8529 
8530 $ HDC dc = Win32::CreateCompatibleDC (NULL); dc asserted;
8531 $ _txStockBitmap = (HBITMAP) Win32::SelectObject (dc, Win32::CreateCompatibleBitmap (dc, 1, 1)); _txStockBitmap asserted;
8532 $ Win32::DeleteObject (Win32::SelectObject (dc, _txStockBitmap)) asserted;
8533 $ Win32::DeleteDC (dc) asserted;
8534 
8535 $ atexit (_txCleanup);
8536 
8537 $ if (_txConsole)
8538  {
8539 $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY);
8540 
8541 $ tx_fpreset();
8542 
8543 $ srand ((unsigned) time (NULL)); //-V202
8544 
8545 $ SetLastError (0);
8546 $ errno = 0;
8547 
8548  #if !defined (__CYGWIN__)
8549 $ _doserrno = 0;
8550  #endif
8551  }
8552 
8553 $ Win32::CoCreateInstance = Win32::CoCreateInstance; // g++ 5.1.0 bug, false warning "defined but not used"
8554 
8555 $ return 1;
8556  }
8557 
8558 //-----------------------------------------------------------------------------------------------------------------
8559 
8560 bool _txCheckSourceCP (int needCP /*= _TX_CODEPAGE*/, bool verbose /*= true*/)
8561  {
8562 $3 const char* sCodePage = NULL;
8563 $ int codePage = 0;
8564 
8565 $ switch (((unsigned const char*) "А) [0]) { case 192: {$ codePage = 1251; sCodePage = "1251."; break; } case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; } case 128: {$ codePage = 866; sCodePage = "866."; break; } case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; } default: {$ codePage = -1; sCodePage = "(Unknown)"; break; } } $ if (codePage != needCP && verbose) { $ *_txTraceSE = ' '; // No stack trace please $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n" "This is NOT an error of TXLib itself. Please note:\n\n" "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your " "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO " "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. " "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n" "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n" "You can continue, but Russian messages and symbols may appear unreadable.", sCodePage, needCP, needCP); } $ return (codePage == needCP); } //----------------------------------------------------------------------------------------------------------------- void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) () { if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL; if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL; static char dllPaths [2][MAX_PATH] = {"", ""}; if (!*dllPaths[0]) { const char dllDir[] = "\\Windows\\"; // dllPaths[0] is relative to the TX Setup directory stored in the Registry char* path = dllPaths[0]; txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH); strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); // dllPaths[1] is relative to TXib.h file used in compilation path = dllPaths[1]; if (strchr (__FILE__, ':')) { strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1); } else { GetCurrentDirectory (MAX_PATH, path); strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1); } if (char* dir = strrchr (path, '\\')) *dir = 0; strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1); } char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = ""; const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547 if (arch) { assert (arch >= dllFileName); //-V547 strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName)); strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName)); strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3); strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch)); } else if (dllFileName) //-V547 //-V2516 { strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1); } HMODULE dll = GetModuleHandle (dllFileName); if (!dll) dll = GetModuleHandle (dllArch); if (!dll) dll = GetModuleHandle (dllName); for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++) { char path [MAX_PATH] = ""; strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i])); size_t len = strlen (path); strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch)); if (!dll) dll = LoadLibrary (path); //-V547 strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName)); if (!dll) dll = LoadLibrary (path); } if (!dll) dll = LoadLibrary (dllArch); if (!dll) dll = LoadLibrary (dllName); if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".", dllName, (arch? "\" / \"" : ""), dllArch); if (!dll) return NULL; void (*addr)() = (void(*)()) GetProcAddress (dll, funcName); if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".", funcName, dllName, (arch? "\" / \"" : ""), dllArch); return addr; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013 #pragma warning (push) #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции #endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку) [0])
8566  {
8567  case 192: {$ codePage = 1251; sCodePage = "1251."; break; }
8568  case 208: {$ codePage = 65001; sCodePage = "UTF-8."; break; }
8569  case 128: {$ codePage = 866; sCodePage = "866."; break; }
8570  case 225: {$ codePage = 20866; sCodePage = "KOI-8, waaat?!"; break; }
8571  default: {$ codePage = -1; sCodePage = "(Unknown)"; break; }
8572  }
8573 
8574 $ if (codePage != needCP && verbose)
8575  {
8576 $ *_txTraceSE = ' '; // No stack trace please
8577 
8578 $ _TX_UNEXPECTED ("\v\t" "\n\n" "WARNING: CHECK TXLib.h file CODEPAGE. Maybe it is %s It should be %d.\n\n"
8579  "This is NOT an error of TXLib itself. Please note:\n\n"
8580  "Do NOT copy-and-paste TXLib.h file contents into a new file and them save it inside your "
8581  "IDE or editor. This can change original TXLib codepage (%d) to another one. Instead, DO "
8582  "use copy / move / cut-and-paste operations in Windows Explorer (Far Manager etc) only. "
8583  "Or, when you see TXLib.h being opened in browser, use 'Save as...' (Ctrl+S) command.\n\n"
8584  "Now you should re-download TXLib.h file from the http://txlib.ru site.\n\n"
8585  "You can continue, but Russian messages and symbols may appear unreadable.",
8586  sCodePage, needCP, needCP);
8587  }
8588 
8589 $ return (codePage == needCP);
8590  }
8591 
8592 //-----------------------------------------------------------------------------------------------------------------
8593 
8594 void (*_txDllImport (const char dllFileName[], const char funcName[], bool required /*= true*/)) ()
8595  {
8596  if (_TX_ARGUMENT_FAILED (dllFileName && *dllFileName)) return NULL;
8597  if (_TX_ARGUMENT_FAILED (funcName && *funcName)) return NULL;
8598 
8599  static char dllPaths [2][MAX_PATH] = {"", ""};
8600 
8601  if (!*dllPaths[0])
8602  {
8603  const char dllDir[] = "\\Windows\\";
8604 
8605  // dllPaths[0] is relative to the TX Setup directory stored in the Registry
8606 
8607  char* path = dllPaths[0];
8608 
8609  txRegQuery ("HKCU\\Software\\TX Library", "ProductDir", path, MAX_PATH);
8610  strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1);
8611 
8612  // dllPaths[1] is relative to TXib.h file used in compilation
8613 
8614  path = dllPaths[1];
8615 
8616  if (strchr (__FILE__, ':'))
8617  {
8618  strncpy_s (path, MAX_PATH, __FILE__, sizeof (__FILE__) - 1);
8619  }
8620  else
8621  {
8622  GetCurrentDirectory (MAX_PATH, path);
8623  strncat_s (path, MAX_PATH, "\\" __FILE__, sizeof ("\\" __FILE__) - 1);
8624  }
8625 
8626  if (char* dir = strrchr (path, '\\')) *dir = 0;
8627 
8628  strncat_s (path, MAX_PATH, dllDir, sizeof (dllDir) - 1);
8629  }
8630 
8631  char dllName[MAX_PATH] = "", dllArch[MAX_PATH] = "";
8632  const char* arch = (dllFileName? strchr (dllFileName, '*') : NULL); //-V547
8633 
8634  if (arch)
8635  {
8636  assert (arch >= dllFileName); //-V547
8637 
8638  strncpy_s (dllName, sizeof (dllName), dllFileName, (size_t) (arch - dllFileName));
8639  strncat_s (dllName, sizeof (dllName), arch+1, sizeof (dllName) - 1 - strlen (dllName));
8640 
8641  strncpy_s (dllArch, sizeof (dllArch), dllFileName, (size_t) (arch - dllFileName));
8642  strncat_s (dllArch, sizeof (dllArch), sizeof (void*) == 8? "64" : "32", 3);
8643  strncat_s (dllArch, sizeof (dllArch), arch+1, sizeof (dllArch) - 1 - strlen (dllArch));
8644  }
8645  else if (dllFileName) //-V547 //-V2516
8646  {
8647  strncat_s (dllName, sizeof (dllName), dllFileName, sizeof (dllName) - 1);
8648  }
8649 
8650  HMODULE dll = GetModuleHandle (dllFileName);
8651 
8652  if (!dll) dll = GetModuleHandle (dllArch);
8653  if (!dll) dll = GetModuleHandle (dllName);
8654 
8655  for (int i = 0; !dll && i < (int) sizearr (dllPaths); i++)
8656  {
8657  char path [MAX_PATH] = "";
8658  strncpy_s (path, sizeof (path), dllPaths[i], sizeof (dllPaths[i]));
8659  size_t len = strlen (path);
8660 
8661  strncpy_s (path + len, sizeof (path) - len, dllArch, sizeof (dllArch));
8662  if (!dll) dll = LoadLibrary (path); //-V547
8663 
8664  strncpy_s (path + len, sizeof (path) - len, dllName, sizeof (dllName));
8665  if (!dll) dll = LoadLibrary (path);
8666  }
8667 
8668  if (!dll) dll = LoadLibrary (dllArch);
8669  if (!dll) dll = LoadLibrary (dllName);
8670 
8671  if (!dll && required) TX_ERROR ("\a" "Cannot load library \"%s%s%s\".",
8672  dllName, (arch? "\" / \"" : ""), dllArch);
8673  if (!dll) return NULL;
8674 
8675  void (*addr)() = (void(*)()) GetProcAddress (dll, funcName);
8676 
8677  if (!addr && required) TX_ERROR ("\a" "Cannot import \"%s\" from library \"%s%s%s\".",
8678  funcName, dllName, (arch? "\" / \"" : ""), dllArch);
8679  return addr;
8680  }
8681 
8682 //-----------------------------------------------------------------------------------------------------------------
8683 
8684 #if defined (_MSC_VER) && (_MSC_VER == 1800) // MSVC 2013
8685  #pragma warning (push)
8686  #pragma warning (disable: 6102) // Использование 'name' из завершившегося ошибкой вызова функции#endif int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue) { if (_TX_ARGUMENT_FAILED (keyName)) return 0; HKEY hive = NULL; #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \ _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 ) if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE; else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER; else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT; else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS; else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG; else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; } #undef EQU_ keyName = strchr (keyName, '\\') + 1; //-V769 assert (keyName > (const char*) 1); HKEY key = NULL; DWORD size = 0; bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS); if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS); if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104 if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS); return size; } #if defined (_MSC_VER) && (_MSC_VER == 1800) #pragma warning (pop) #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/) { $1 if (!_txInitialized) _txInitialized = _txInitialize(); $ if (HWND wnd = txWindow()) { $ SetLastErrorEx (ERROR_INVALID_DATA, 0); $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!")); $ return wnd; } $ if (!_txIsDll) { $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe $ (void) AddAtom ("_txMain"); //-V530 } $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048 $ _txRunning = false; // Store the size $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) }; $ if (centered) { size.cx *= -1; size.cy *= -1; } // In Thread, where REAL creation lies... $ unsigned id = 0; $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id); $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL; $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT); $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL; $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL; $ HWND console = Win32::GetConsoleWindow(); $ DWORD proc = 0; $ GetWindowThreadProcessId (console, &proc); $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable())) {$ ShowWindow (console, TX_CONSOLE_MODE); } $ HMENU menu = GetSystemMenu (txWindow(), false); if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); } $ Win32::GdiSetBatchLimit (1); $ SetLastError (0); $ errno = 0; #if !defined (__CYGWIN__) $ _doserrno = 0; #endif $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- HWND txCreateExtraWindow (CREATESTRUCT createData) { $1 if (_TX_TXWINDOW_FAILED()) return NULL; $ volatile HWND wnd = NULL; $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd; $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted; $ _txWaitFor (wnd, 5*_TX_TIMEOUT); $ return wnd; } //----------------------------------------------------------------------------------------------------------------- bool txSetDefaults (HDC dc /*= txDC()*/) { $1 if (dc == txDC()) txUpdateWindow (false); //-V601 $ txAutoLock _lock; $ RECT r = {}; $ GetClientRect (Win32::GetConsoleWindow(), &r); $ SIZE szCon = { r.right - r.left, r.bottom - r.top }; $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}}; $ GetConsoleScreenBufferInfo (out, &con); $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1), (short) (con.srWindow.Bottom - con.srWindow.Top + 1) }; //{ Set defaults for graphics layer $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted; $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted; $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT), dc) asserted; $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted; $ Win32::SetBkMode (dc, TRANSPARENT) asserted; $ Win32::SetROP2 (dc, R2_COPYPEN) asserted; $ Win32::SetStretchBltMode (dc, HALFTONE) asserted; //} $ if (dc != txDC()) {$ return true; } //{ Set defaults for console layer $ POINT szCanvas = txGetExtent (dc); $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)? Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT) : Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, _txCanvas_BackBuf[1]); //} //{ Scroll the console for text to go above top of window and don't mix with graphics $ if (con.dwCursorPosition.X) _putch ('\n'); $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top); $ con.srWindow.Top = (short) (con.srWindow.Top + delta); $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta); $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) }; $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY }; $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up $ con.dwCursorPosition.X = 0; $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta); $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window" SetConsoleWindowInfo (out, true, &con.srWindow)) || (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer SetConsoleCursorPosition (out, con.dwCursorPosition)); //} $ txUpdateWindow (true); //-V601 return true; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool txOK() { return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you? _txCanaryLast == 0x5E2E2E5E && _txCanvas_OK() #if defined (_MSC_VER) && _CrtCheckMemory() #endif ); } //----------------------------------------------------------------------------------------------------------------- //{ Cleanup //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain. // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize(). void _txOnCExit() { OutputDebugString ("\n"); $5 _txCleanup(); _TX_CALLv (Win32::_cexit, ()); } //----------------------------------------------------------------------------------------------------------------- void _txOnExit (int retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode); Win32::exit (retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnExitProcess (unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode); Win32::ExitProcess (retcode); } //----------------------------------------------------------------------------------------------------------------- bool _txOnTerminateProcess (HANDLE process, unsigned retcode) { if (retcode != 0) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode); } $5 _txCleanup(); if (retcode != 0) txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode); return Win32::TerminateProcess (process, retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalExit (int retcode) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode); _TX_CALLv (Win32::FatalExit, (retcode)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode); Win32::TerminateProcess (GetCurrentProcess(), retcode); } //----------------------------------------------------------------------------------------------------------------- void _txOnFatalAppExitA (unsigned action, const char message[]) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message); $5 _txCleanup(); txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message); _TX_CALLv (Win32::FatalAppExitA, (action, message)); txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } //----------------------------------------------------------------------------------------------------------------- BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type) { OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type); $5 switch (type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: $ _txExit = true; $ _txCleanup(); case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: default: break; //-V2522 } $ return false; } //----------------------------------------------------------------------------------------------------------------- void _txCleanup() { if (!_txInitialized) return; else _txInitialized = false; //-V601 $3 _txRunning = false; $ _txConsole_IsBlinking = false; $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR); $ txSetWindowsHook (NULL); $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ unsigned thread = GetCurrentThreadId(); $ HWND wnd = (canvas)? canvas : console; $ bool externTerm = (thread != _txMainThreadId && thread != _txCanvas_ThreadId); $ DWORD parent = 0; $ int isParentWaitable = _txIsParentWaitable (&parent); $ bool waitableParent = !externTerm && isParentWaitable; $ if (canvas) {$ txSleep (5*_txWindowUpdateInterval); } $ if (_txConsole) { $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ if (console) { $ EnableWindow (console, true); $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } } $ if (_txMain && !externTerm && canvas) {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); } $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ bool paused = false; $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId)) { $ if (wnd) { $ if (isParentWaitable >= 0) {$ _txActivateWindow (wnd, 0x08); } $ EnableWindow (wnd, true); } $ if (console && isParentWaitable >= 0) { $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" : (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f"); $ paused = true; } } $ if (_txConsole && _txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (txWindow()) {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); } $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT); $ txSpeak (NULL); $ txPlayVideo (NULL); $ delete _txCanvas_UserDCs; $ _txCanvas_UserDCs = NULL; $ if (GetCurrentThreadId() != _txMainThreadId) {$ SuspendThread (_txMainThread); } //-V720 $ if (GetCurrentThreadId() != _txCanvas_ThreadId) {$ SuspendThread (_txCanvas_Thread); } //-V720 $ if (_txMainThread) {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; } $ if (_txCanvas_Thread) {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; } $ if (!txWindow()) {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; } $ bool parentKilled = false; $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT)) { $ console = Win32::GetConsoleWindow(); $ if (parent) {$ parentKilled = _txKillProcess (parent); } $ if (parent && !parentKilled) { $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } } $ if (_txConsole) {$ _txSetWindowText (console, NULL); } $ if (_txMain && _txConsole) {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560 $ std::cout.flush(); $ std::cerr.flush(); $ std::clog.flush(); $ _flushall(); $ _txSymGetFromAddr (NULL); // That's all, folks _TX_ON_DEBUG (OutputDebugString ("\n"); OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n"); OutputDebugString ("\n")); } //----------------------------------------------------------------------------------------------------------------- int txPause (const char* message /*= NULL*/, ...) { $3 bool wine = !!Win32::wine_get_version; $ HWND canvas = txWindow(); $ HWND console = Win32::GetConsoleWindow(); $ HWND wnd = (canvas)? canvas : console; $ bool istty0 = _txIsTTY (0); $ int attr = txGetConsoleAttr(); $ int oldCP = GetConsoleOutputCP(); $ SetConsoleOutputCP (_TX_CODEPAGE); if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; } if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); } else {$ message++; } if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); } else {$ message++; } $ _txActivateWindow (wnd, 0x08); $ va_list args; $ va_start (args, message); $ vfprintf (stderr, message, args); $ txOutputDebugPrintf (message, args); $ va_end (args); $ fflush (stderr); $ txSleep(); $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF }; $ _TX_CALL (Win32::FlashWindowEx, (&flash)); $ int ch = EOF; if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ for (int i = 1; ; i++) //-V2530 { $ Sleep (_txWindowUpdateInterval); if (!istty0 && !canvas) {$ break; } // No need to run and hide if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something. if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not. if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas))) {$ TX_ERROR ("Похоже, программа зависла :("); break; } if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas))) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла"); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
8687 #endif
8688 
8689 int txRegQuery (const char* keyName, const char* valueName, void* value, size_t szValue)
8690  {
8691  if (_TX_ARGUMENT_FAILED (keyName)) return 0;
8692 
8693  HKEY hive = NULL;
8694 
8695  #define EQU_(name1, name2) ( _strnicmp (keyName, name1 "\\", sizeof (name1)) == 0 || \
8696  _strnicmp (keyName, name2 "\\", sizeof (name2)) == 0 )
8697 
8698  if (EQU_("HKLM", "HKEY_LOCAL_MACHINE")) hive = HKEY_LOCAL_MACHINE;
8699  else if (EQU_("HKCU", "HKEY_CURRENT_USER")) hive = HKEY_CURRENT_USER;
8700  else if (EQU_("HKCR", "HKEY_CLASSES_ROOT")) hive = HKEY_CLASSES_ROOT;
8701  else if (EQU_("HKU", "HKEY_USERS")) hive = HKEY_USERS;
8702  else if (EQU_("HKCC", "HKEY_CURRENT_CONFIG")) hive = HKEY_CURRENT_CONFIG;
8703 
8704  else { _TX_ARGUMENT_FAILED (("keyName должно начинаться с HKLM\\, HKCU\\, HKCR\\, HKU\\ или HKCC\\ ", hive)); return 0; }
8705 
8706  #undef EQU_
8707 
8708  keyName = strchr (keyName, '\\') + 1; //-V769
8709  assert (keyName > (const char*) 1);
8710 
8711  HKEY key = NULL;
8712  DWORD size = 0;
8713 
8714  bool ok = (RegOpenKeyEx (hive, keyName, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS);
8715  if (ok) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, NULL, &size) == ERROR_SUCCESS);
8716  if (ok && value && size < szValue) ok &= (RegQueryValueEx (key, valueName, NULL, NULL, (BYTE*) value, &size) == ERROR_SUCCESS); //-V104
8717  if (key) ok &= (RegCloseKey (key) == ERROR_SUCCESS);
8718 
8719  return size;
8720  }
8721 
8722 #if defined (_MSC_VER) && (_MSC_VER == 1800)
8723  #pragma warning (pop)
8724 #endif
8725 
8726 #endif // TX_COMPILED
8727 
8728 //}
8729 //-----------------------------------------------------------------------------------------------------------------
8730 
8731 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
8732 
8733 HWND txCreateWindow (double sizeX, double sizeY, bool centered /*= true*/)
8734  {
8735 $1 if (!_txInitialized) _txInitialized = _txInitialize();
8736 
8737 $ if (HWND wnd = txWindow())
8738  {
8739 $ SetLastErrorEx (ERROR_INVALID_DATA, 0);
8740 $ _TX_ON_DEBUG (TX_ERROR ("\a" "Окно рисования уже создано!"));
8741 $ return wnd;
8742  }
8743 
8744 $ if (!_txIsDll)
8745  {
8746 $ _txMain = ! FindAtom ("_txMain"); // Not a thread-safe
8747 $ (void) AddAtom ("_txMain"); //-V530
8748  }
8749 
8750 $ if (_txWindowUpdateInterval < 10) {$ _txWindowUpdateInterval = 10; } //-V1048
8751 
8752 $ _txRunning = false;
8753 
8754  // Store the size
8755 
8756 $ static SIZE size = { ROUND (sizeX), ROUND (sizeY) };
8757 $ if (centered) { size.cx *= -1; size.cy *= -1; }
8758 
8759  // In Thread, where REAL creation lies...
8760 
8761 $ unsigned id = 0;
8762 $ _txCanvas_Thread = (HANDLE) Win32::_beginthreadex (NULL, 0, _txCanvas_ThreadProc, &size, 0, &id);
8763 
8764 $ if (!_txCanvas_Thread) return TX_DEBUG_ERROR ("\a" "Cannot start canvas thread."), (HWND) NULL;
8765 
8766 $ _txWaitFor (_txRunning, 10*_TX_TIMEOUT);
8767 
8768 $ if (!_txRunning) return TX_DEBUG_ERROR ("\a" "Cannot create canvas window."), (HWND) NULL;
8769 $ if (!txOK()) return TX_DEBUG_ERROR ("\a" "Canvas window is not OK."), (HWND) NULL;
8770 
8771 $ HWND console = Win32::GetConsoleWindow();
8772 
8773 $ DWORD proc = 0;
8774 $ GetWindowThreadProcessId (console, &proc);
8775 
8776 $ if (console && (proc == GetCurrentProcessId() || _txIsParentWaitable()))
8777  {$ ShowWindow (console, TX_CONSOLE_MODE); }
8778 
8779 $ HMENU menu = GetSystemMenu (txWindow(), false);
8780  if (menu) {$ CheckMenuItem (menu, _TX_IDM_CONSOLE, (console? (IsWindowVisible (console)? MF_CHECKED : 0) : MF_DISABLED)); }
8781 
8782 $ Win32::GdiSetBatchLimit (1);
8783 
8784 $ SetLastError (0);
8785 
8786 $ errno = 0;
8787 
8788  #if !defined (__CYGWIN__)
8789 $ _doserrno = 0;
8790  #endif
8791 
8792 $ return txWindow();
8793  }
8794 
8795 //-----------------------------------------------------------------------------------------------------------------
8796 
8797 HWND txCreateExtraWindow (CREATESTRUCT createData)
8798  {
8799 $1 if (_TX_TXWINDOW_FAILED()) return NULL;
8800 
8801 $ volatile HWND wnd = NULL;
8802 $ createData.hInstance = (HINSTANCE)(uintptr_t) &wnd;
8803 
8804 $ PostMessage (txWindow(), _TX_WM_CREATEWND, 0, (LPARAM) &createData) asserted;
8805 
8806 $ _txWaitFor (wnd, 5*_TX_TIMEOUT);
8807 
8808 $ return wnd;
8809  }
8810 
8811 //-----------------------------------------------------------------------------------------------------------------
8812 
8813 bool txSetDefaults (HDC dc /*= txDC()*/)
8814  {
8815 $1 if (dc == txDC()) txUpdateWindow (false); //-V601
8816 $ txAutoLock _lock;
8817 
8818 $ RECT r = {};
8819 $ GetClientRect (Win32::GetConsoleWindow(), &r);
8820 $ SIZE szCon = { r.right - r.left, r.bottom - r.top };
8821 
8822 $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE);
8823 
8824 $ CONSOLE_SCREEN_BUFFER_INFO con = {{80, 25}, {}, 0, {0, 0, 80-1, 25-1}, {80, 25}};
8825 $ GetConsoleScreenBufferInfo (out, &con);
8826 
8827 $ SIZE szTxt = { (short) (con.srWindow.Right - con.srWindow.Left + 1),
8828  (short) (con.srWindow.Bottom - con.srWindow.Top + 1) };
8829 
8830 //{ Set defaults for graphics layer
8831 
8832 $ _txBuffer_Select (Win32::GetStockObject (WHITE_PEN), dc) asserted;
8833 $ _txBuffer_Select (Win32::GetStockObject (WHITE_BRUSH), dc) asserted;
8834 
8835 $ _txBuffer_Select (Win32::CreateFont (szCon.cy/szTxt.cy, szCon.cx/szTxt.cx,
8836  0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
8837  RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
8838  DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT),
8839  dc) asserted;
8840 
8841 $ (Win32::SetTextColor (dc, TX_WHITE) != CLR_INVALID) asserted;
8842 $ Win32::SetBkMode (dc, TRANSPARENT) asserted;
8843 
8844 $ Win32::SetROP2 (dc, R2_COPYPEN) asserted;
8845 $ Win32::SetStretchBltMode (dc, HALFTONE) asserted;
8846 
8847 //}
8848 
8849 $ if (dc != txDC())
8850  {$ return true; }
8851 
8852 //{ Set defaults for console layer
8853 
8854 $ POINT szCanvas = txGetExtent (dc);
8855 
8856 $ HGDIOBJ font = txFontExist (TX_CONSOLE_FONT)?
8857  Win32::CreateFont (szCanvas.y/szTxt.cy, szCanvas.x/szTxt.cx,
8858  0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
8859  RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
8860  DEFAULT_QUALITY, FIXED_PITCH, TX_CONSOLE_FONT)
8861  :
8862  Win32::GetStockObject (SYSTEM_FIXED_FONT);
8863 
8864 $ _txBuffer_Select (font, _txCanvas_BackBuf[1]);
8865 //}
8866 
8867 //{ Scroll the console for text to go above top of window and don't mix with graphics
8868 
8869 $ if (con.dwCursorPosition.X) _putch ('\n');
8870 
8871 $ short delta = (short) (con.dwCursorPosition.Y - con.srWindow.Top);
8872 
8873 $ con.srWindow.Top = (short) (con.srWindow.Top + delta);
8874 $ con.srWindow.Bottom = (short) (con.srWindow.Bottom + delta);
8875 
8876 $ SMALL_RECT src = { 0, 0, (short) (con.dwSize.X - 1), (short) (con.dwSize.Y - 1) };
8877 $ CHAR_INFO fill = { {' '}, FOREGROUND_LIGHTGRAY };
8878 $ COORD dest = { 0, (short) -delta }; // New UL-corner of src, scroll up
8879 
8880 $ con.dwCursorPosition.X = 0;
8881 $ con.dwCursorPosition.Y = (short) (con.dwCursorPosition.Y - delta);
8882 
8883 $ (con.srWindow.Bottom < con.dwSize.Y && // Move the "window"
8884  SetConsoleWindowInfo (out, true, &con.srWindow))
8885  ||
8886  (ScrollConsoleScreenBuffer (out, &src, NULL, dest, &fill), // Or scroll the buffer
8887  SetConsoleCursorPosition (out, con.dwCursorPosition));
8888 //}
8889 
8890 $ txUpdateWindow (true); //-V601
8891 
8892  return true;
8893  }
8894 
8895 #endif // TX_COMPILED
8896 
8897 //-----------------------------------------------------------------------------------------------------------------
8898 
8899 inline bool txOK()
8900  {
8901  return (_txCanaryFirst == 0x776F656D && // Too well-known values to use constants. You know these values, don't you?
8902  _txCanaryLast == 0x5E2E2E5E &&
8903  _txCanvas_OK()
8904 
8905  #if defined (_MSC_VER)
8906  && _CrtCheckMemory()
8907  #endif
8908  );
8909  }
8910 
8911 //-----------------------------------------------------------------------------------------------------------------
8912 //{ Cleanup
8913 //-----------------------------------------------------------------------------------------------------------------
8914 
8915 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
8916 
8917 // Implicit std(MSVCRT.dll)::_cexit() call before _txCleanup can lead to hangs in _cexit handlers chain.
8918 // So redefining ::std::_cexit(). Do it dynamically via PE Import Table hook to avoid duplicate symbols
8919 // if several modules linked together include TXLib.h. See _txSetProcAddress() call in _txInitialize().
8920 
8921 void _txOnCExit()
8922  {
8923  OutputDebugString ("\n");
8924 
8925 $5 _txCleanup();
8926 
8927  _TX_CALLv (Win32::_cexit, ());
8928  }
8929 
8930 //-----------------------------------------------------------------------------------------------------------------
8931 
8932 void _txOnExit (int retcode)
8933  {
8934  if (retcode != 0)
8935  {
8936  OutputDebugString ("\n");
8937  txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode);
8938  }
8939 
8940 $5 _txCleanup();
8941 
8942  if (retcode != 0)
8943  txOutputDebugPrintf ("%s - WARNING: calling Win32::exit (%d)\n", _TX_VERSION, retcode);
8944 
8945  Win32::exit (retcode);
8946  }
8947 
8948 //-----------------------------------------------------------------------------------------------------------------
8949 
8950 void _txOnExitProcess (unsigned retcode)
8951  {
8952  if (retcode != 0)
8953  {
8954  OutputDebugString ("\n");
8955  txOutputDebugPrintf ("%s - WARNING: %s (%u) called\n", _TX_VERSION, __func__, retcode);
8956  }
8957 
8958 $5 _txCleanup();
8959 
8960  if (retcode != 0)
8961  txOutputDebugPrintf ("%s - WARNING: calling Win32::ExitProcess (%u)\n", _TX_VERSION, retcode);
8962 
8963  Win32::ExitProcess (retcode);
8964  }
8965 
8966 //-----------------------------------------------------------------------------------------------------------------
8967 
8968 bool _txOnTerminateProcess (HANDLE process, unsigned retcode)
8969  {
8970  if (retcode != 0)
8971  {
8972  OutputDebugString ("\n");
8973  txOutputDebugPrintf ("%s - WARNING: %s (0x%p, %u) called\n", _TX_VERSION, __func__, process, retcode);
8974  }
8975 
8976 $5 _txCleanup();
8977 
8978  if (retcode != 0)
8979  txOutputDebugPrintf ("%s - WARNING: calling Win32::TerminateProcess (0x%p, %u)\n", _TX_VERSION, process, retcode);
8980 
8981  return Win32::TerminateProcess (process, retcode);
8982  }
8983 
8984 //-----------------------------------------------------------------------------------------------------------------
8985 
8986 void _txOnFatalExit (int retcode)
8987  {
8988  OutputDebugString ("\n");
8989  txOutputDebugPrintf ("%s - WARNING: %s:%d called\n", _TX_VERSION, __func__, retcode);
8990 
8991 $5 _txCleanup();
8992 
8993  txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalExit (%d)\n", _TX_VERSION, retcode);
8994  _TX_CALLv (Win32::FatalExit, (retcode));
8995 
8996  txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (%d)\n", _TX_VERSION, retcode);
8997  Win32::TerminateProcess (GetCurrentProcess(), retcode);
8998  }
8999 
9000 //-----------------------------------------------------------------------------------------------------------------
9001 
9002 void _txOnFatalAppExitA (unsigned action, const char message[])
9003  {
9004  OutputDebugString ("\n");
9005  txOutputDebugPrintf ("%s - WARNING: %s (%u, \"%s\") called\n", _TX_VERSION, __func__, action, message);
9006 
9007 $5 _txCleanup();
9008 
9009  txOutputDebugPrintf ("%s - WARNING: calling Win32::FatalAppExitA (%u, %s)\n", _TX_VERSION, action, message);
9010  _TX_CALLv (Win32::FatalAppExitA, (action, message));
9011 
9012  txOutputDebugPrintf ("%s - WARNING: Win32::FatalExit() failure, calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION);
9013  Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE);
9014  }
9015 
9016 //-----------------------------------------------------------------------------------------------------------------
9017 
9018 BOOL WINAPI _txOnConsoleCtrlEvent (DWORD type)
9019  {
9020  OutputDebugString ("\n");
9021  txOutputDebugPrintf ("%s - WARNING: %s (0x%04lX) called\n", _TX_VERSION, __func__, (unsigned long) type);
9022 
9023 $5 switch (type)
9024  {
9025  case CTRL_LOGOFF_EVENT:
9026  case CTRL_SHUTDOWN_EVENT: $ _txExit = true;
9027  $ _txCleanup();
9028  case CTRL_C_EVENT:
9029  case CTRL_CLOSE_EVENT:
9030  case CTRL_BREAK_EVENT:
9031 
9032  default: break; //-V2522
9033  }
9034 
9035 $ return false;
9036  }
9037 
9038 //-----------------------------------------------------------------------------------------------------------------
9039 
9040 void _txCleanup()
9041  {
9042  if (!_txInitialized) return;
9043  else _txInitialized = false; //-V601
9044 
9045 $3 _txRunning = false;
9046 $ _txConsole_IsBlinking = false;
9047 
9048 $ txSetProgress (100, (!_txErrors)? Win32::TBPF_PAUSED : Win32::TBPF_ERROR);
9049 
9050 $ txSetWindowsHook (NULL);
9051 
9052 $ HWND canvas = txWindow();
9053 $ HWND console = Win32::GetConsoleWindow();
9054 $ unsigned thread = GetCurrentThreadId();
9055 
9056 $ HWND wnd = (canvas)? canvas : console;
9057 
9058 $ bool externTerm = (thread != _txMainThreadId &&
9059  thread != _txCanvas_ThreadId);
9060 
9061 $ DWORD parent = 0;
9062 $ int isParentWaitable = _txIsParentWaitable (&parent);
9063 $ bool waitableParent = !externTerm && isParentWaitable;
9064 
9065 $ if (canvas)
9067 
9068 $ if (_txConsole)
9069  {
9070 $ if (_txMain) txSetConsoleAttr (FOREGROUND_LIGHTGRAY);
9071 
9072 $ if (console)
9073  {
9074 $ EnableWindow (console, true);
9075 $ _txSetWindowText (console, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */);
9076  }
9077  }
9078 
9079 $ if (_txMain && !externTerm && canvas)
9080  {$ _txSetWindowText (canvas, " [ЗАВЕРШЕНО]", " [FINISHED]", 2, L"\x0417" /* 'З' */ L"\x0046" /* 'F' */); }
9081 
9082 $ std::cout.flush();
9083 $ std::cerr.flush();
9084 $ std::clog.flush();
9085 $ _flushall();
9086 
9087 $ bool paused = false;
9088 $ if (((canvas? _txMain : _txConsole) && !_txExit) || (_txErrors && thread == _txMainThreadId))
9089  {
9090 $ if (wnd)
9091  {
9092 $ if (isParentWaitable >= 0)
9093  {$ _txActivateWindow (wnd, 0x08); }
9094 
9095 $ EnableWindow (wnd, true);
9096  }
9097 
9098 $ if (console && isParentWaitable >= 0)
9099  {
9100 $ txPause ((_txErrors)? "\f\n" "[Press F to Pay Respects...]" :
9101  (!canvas && _txIsTTY (0))? "\f\n" "[Нажмите любую клавишу для завершения]" : "\f");
9102 
9103 $ paused = true;
9104  }
9105  }
9106 
9107 $ if (_txConsole && _txWatchdogTimeout >= 0)
9108  {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); }
9109 
9110 $ if (txWindow())
9111  {$ SendNotifyMessage (txWindow(), WM_DESTROY, 0, 0); }
9112 
9113 $ _txWaitFor (!txWindow(), 5*_TX_TIMEOUT);
9114 
9115 $ txSpeak (NULL);
9116 $ txPlayVideo (NULL);
9117 
9118 $ delete _txCanvas_UserDCs;
9119 $ _txCanvas_UserDCs = NULL;
9120 
9121 $ if (GetCurrentThreadId() != _txMainThreadId)
9122  {$ SuspendThread (_txMainThread); } //-V720
9123 $ if (GetCurrentThreadId() != _txCanvas_ThreadId)
9124  {$ SuspendThread (_txCanvas_Thread); } //-V720
9125 
9126 $ if (_txMainThread)
9127  {$ CloseHandle (_txMainThread) asserted; _txMainThread = NULL; }
9128 $ if (_txCanvas_Thread)
9129  {$ CloseHandle (_txCanvas_Thread) asserted; _txCanvas_Thread = NULL; }
9130 
9131 $ if (!txWindow())
9132  {$ DeleteCriticalSection (&_txCanvas_LockBackBuf); CRITICAL_SECTION zero = {0, -1}; _txCanvas_LockBackBuf = zero; }
9133 
9134 $ bool parentKilled = false;
9135 $ if (waitableParent && paused && _txNOP (_TX_ALLOW_KILL_PARENT))
9136  {
9137 $ console = Win32::GetConsoleWindow();
9138 
9139 $ if (parent)
9140  {$ parentKilled = _txKillProcess (parent); }
9141 
9142 $ if (parent && !parentKilled)
9143  {
9144 $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1
9145 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1
9146  }
9147  }
9148 
9149 $ if (_txConsole)
9150  {$ _txSetWindowText (console, NULL); }
9151 
9152 $ if (_txMain && _txConsole)
9153  {$ _txConsole_Detach (waitableParent && !parentKilled && !externTerm); } //-V560
9154 
9155 $ std::cout.flush();
9156 $ std::cerr.flush();
9157 $ std::clog.flush();
9158 $ _flushall();
9159 
9160 $ _txSymGetFromAddr (NULL);
9161 
9162  // That's all, folks
9163 
9164  _TX_ON_DEBUG (OutputDebugString ("\n");
9165  OutputDebugString (_TX_VERSION " - FINISHED: " _TX_MODULE "\n");
9166  OutputDebugString ("\n"));
9167  }
9168 
9169 //-----------------------------------------------------------------------------------------------------------------
9170 
9171 int txPause (const char* message /*= NULL*/, ...)
9172  {
9173 $3 bool wine = !!Win32::wine_get_version;
9174 
9175 $ HWND canvas = txWindow();
9176 $ HWND console = Win32::GetConsoleWindow();
9177 $ HWND wnd = (canvas)? canvas : console;
9178 $ bool istty0 = _txIsTTY (0);
9179 
9180 $ int attr = txGetConsoleAttr();
9181 
9182 $ int oldCP = GetConsoleOutputCP();
9183 $ SetConsoleOutputCP (_TX_CODEPAGE);
9184 
9185  if (!message) {$ message = "[Нажмите любую клавишу для продолжения]"; }
9186 
9187  if (*message != '\f') {$ _txSetWindowText (wnd, " [Нажмите клавишу...]", " [Press a key...]"); }
9188  else {$ message++; }
9189 
9190  if (*message != '\v') {$ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); }
9191  else {$ message++; }
9192 
9193 $ _txActivateWindow (wnd, 0x08);
9194 
9195 $ va_list args;
9196 $ va_start (args, message);
9197 $ vfprintf (stderr, message, args);
9198 $ txOutputDebugPrintf (message, args);
9199 $ va_end (args);
9200 
9201 $ fflush (stderr);
9202 $ txSleep();
9203 
9204 $ Win32::FLASHWINFO flash = { sizeof (flash), wnd, FLASHW_ALL | FLASHW_TIMERNOFG, 0xFFFFFFFF };
9205 $ _TX_CALL (Win32::FlashWindowEx, (&flash));
9206 
9207 $ int ch = EOF;
9208  if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); }
9209 
9210 $ for (int i = 1; ; i++) //-V2530
9211  {
9212 $ Sleep (_txWindowUpdateInterval);
9213 
9214  if (!istty0 && !canvas) {$ break; } // No need to run and hide
9215 
9216  if (!wine && (ch = _txGetInput()) != EOF) {$ break; } // Somebody hit something.
9217 
9218  if (canvas && !_txCanvas_ThreadId) {$ break; } // There was a window, and now there is not.
9219 
9220  if (!Win32::GetConsoleWindow()) {$ break; } // Console was destroyed
9221 
9222  if (_TX_CALL (Win32::GhostWindowFromHungWindow, (canvas)))
9223  {$ TX_ERROR ("Похоже, программа зависла :("); break; }
9224 
9225  if (canvas && _TX_CALL (Win32::IsHungAppWindow, (canvas)))
9226  {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа-таки зависла); break; } if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL)) {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; } if (!wine && !(i % 100500)) {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); } } if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); } $ _txSetWindowText (wnd, NULL); $ fprintf (stderr, "\n"); if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ SetConsoleOutputCP (oldCP); $ txSetConsoleAttr (attr); $ return ch; } //----------------------------------------------------------------------------------------------------------------- int _txGetInput() { $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE); $ int ch = EOF; $ DWORD nChars = 0; $ if (GetConsoleMode (con, &nChars) == 0 && PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL)) { $ ch = (nChars)? fgetc (stdin) : EOF; } else if (_kbhit()) { $ ch = _getch(); } #if defined (_MSC_VER) && (_MSC_VER < 1700) else if (fseek (stdin, 1, SEEK_CUR) != EOF) { $ (void) fseek (stdin, -1, SEEK_CUR); $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta } #endif if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); } $ return ch; } //----------------------------------------------------------------------------------------------------------------- bool _txIsTTY (int fd) { $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR; } //----------------------------------------------------------------------------------------------------------------- int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/, int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/) { struct tools { static LRESULT getWindowText (HWND window, wchar_t text[], size_t size) { $3 memset (text, 0, size * sizeof (*text)); $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } static LRESULT setWindowText (HWND window, wchar_t text[]) { $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL); } }; $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib"; $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib"; $ if (!textRus) { $ tools::setWindowText (wnd, oldTitle); $ return -1; } $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1; $ memcpy (oldTitle, title, sizeof (oldTitle)); $ if (textRus) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; } if (!checkLetters) {$ return -2; } } $ if (textEng) { $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len); $ tools::setWindowText (wnd, title); $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1); if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; } if (!checkLetters) {$ return -2; } } $ return -3; } //----------------------------------------------------------------------------------------------------------------- int _txIsParentWaitable (DWORD* parentPID /*= NULL*/) { $4 PROCESSENTRY32* info = _txFindProcess(); $ if (!info) return 0; $ info = _txFindProcess (info->th32ParentProcessID); $ if (!info) return 0; $ char parent [MAX_PATH] = ""; $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1); $ if (parentPID) *parentPID = info->th32ProcessID; $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS; $ char* ctx = NULL; $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx)) { $ char* gp = strchr (p, ':'); $ if (gp) { $ *gp++ = 0; $ if (_stricmp (p, parent) != 0) { continue; } $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid {$ return islower ((unsigned char) *gp)? +1 : -1; } } else { $ if (_stricmp (p, parent) == 0) {$ return islower ((unsigned char) *p)? +1 : -1; } } } $ return 0; } //----------------------------------------------------------------------------------------------------------------- void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions { $3 if (_TX_ARGUMENT_FAILED (timeout)) return; $ Sleep (*(int*) timeout); //-V206 $ OutputDebugString ("\n"); txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection... _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206 $ DWORD parent = 0; $ if (_txIsParentWaitable (&parent)) { txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n", _TX_VERSION, __func__, (unsigned long) parent); $ _txKillProcess (parent); $ HWND console = GetConsoleWindow(); $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1 } txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__); $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Tools //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< // You are here, little hacker? int _txTaskKill (const char i[] /*= NULL*/, const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/, unsigned x /*= 0*/) { // ...so tired of it already... #define name i // Great name! #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine #define pid x // Another great name, isn't it? $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L""; if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); } $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return 0; //-V547 $ int killed = 0; $ PROCESSENTRY32 info = { sizeof (info) }; $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) { bool kill = false; if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560 if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; } if (!kill) { wchar_t cmdLineW[_TX_BUFSIZE] = L""; if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; } if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; } } if (kill) { $ if (_txKillProcess (info.th32ProcessID)) {$ killed++; } } } $ CloseHandle (sshot); $ return killed; #undef name #undef cmdLine #undef pid } //----------------------------------------------------------------------------------------------------------------- bool _txKillProcess (DWORD pid) { $3 if (_TX_ARGUMENT_FAILED (pid)) return false; $ HANDLE token = INVALID_HANDLE_VALUE; $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted; $ LUID luid = {}; $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted; $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}}; $ TOKEN_PRIVILEGES old = {}; $ DWORD oldSz = 0; $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted; $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid); $ if (!proc) return false; $ bool ok = !!Win32::TerminateProcess (proc, 0); $ CloseHandle (proc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/) { $4 static PROCESSENTRY32 info = { sizeof (info) }; $ if (!pid) return &info; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); $ assert (sshot); if (!sshot) return NULL; //-V547 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info)) if (info.th32ProcessID == pid) break; $ CloseHandle (sshot); $ return &info; } //----------------------------------------------------------------------------------------------------------------- bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/) { $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false; $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547 $ if (pid == (unsigned) _getpid()) { $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1); $ return true; } $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (!proc) {$ return false; } $ Win32::PROCESS_BASIC_INFORMATION pbi = {}; $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0); // Should use ReadProcessMemory() because the info is actually in another address space $ Win32::PEB peb = {}; if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); } $ Win32::RTL_USER_PROCESS_PARAMETERS params = {}; if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); } $ *cmdLine = 0; if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106 MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202 NULL); } $ CloseHandle (proc) asserted; $ return ok; } //----------------------------------------------------------------------------------------------------------------- #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) ) IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/) { $4 assert (module); $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0); $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew); $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE && ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL; } //----------------------------------------------------------------------------------------------------------------- // TXLib continues to hack the reality to make your life better, sweeter and easier uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/, HMODULE module /*= NULL*/, bool debug /*= false*/) { $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module); $ if (_TX_ARGUMENT_FAILED (funcName)) return 0; $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0; $ if (!module) module = GetModuleHandle (NULL); $ if (!module) return 0; $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL; $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL; $ if (useHotPatching && oldFunc) { $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction) $ DWORD oldRights = 0; $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0; // Overwrite oldFunc prolog with JMP trampoline to newFunc. // Calling oldFunc from any location will lead to newFunc call anyway. $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz); $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights); $ return (uintptr_t) oldFunc; } // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html. $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module); if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; } $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset); $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL; $ char* impDll = NULL; $ char* impName = NULL; $ void** impPtr = NULL; $ bool found = false; for (; desc->Name; desc++) { $ impDll = RVA_ (char*, module, desc->Name); $ if (dllName && _stricmp (impDll, dllName) != 0) continue; $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk), thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk); thunk0 && thunk1 && thunk1->u1.Function; thunk0++, thunk1++) { impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name; impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL; if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName); if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) || (impName && _stricmp (funcName, impName) == 0)) //-V560 { found = true; break; } } $ if (found) break; } if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n", funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found")); $ if (!found) return 0; $ DWORD rights = PAGE_READWRITE; $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0; $ *(uintptr_t*) impPtr = newFunc; $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights); $ return (uintptr_t) oldFunc; } #undef RVA_ //----------------------------------------------------------------------------------------------------------------- bool _txInDll() { $4 MODULEENTRY32 mod = { sizeof (mod) }; $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); $ assert (sshot); if (!sshot) return false; //-V547 $ bool inDll = false; $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod)) { $ if (!mod.modBaseAddr) continue; $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr); $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0); $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104 {$ break; } } $ CloseHandle (sshot); $ return inDll; } //----------------------------------------------------------------------------------------------------------------- bool _txIsConsoleSubsystem() { $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders(); $ return ntHdr && ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC && (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI); } //----------------------------------------------------------------------------------------------------------------- bool _txIsBadReadPtr (const void* address) { MEMORY_BASIC_INFORMATION mbi = {}; if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; return !(mbi.Protect & readRights); } //----------------------------------------------------------------------------------------------------------------- void _txActivateWindow (HWND wnd, unsigned mode) { $1 EnableWindow (wnd, true); $ if (mode & 0x10) { $ ShowWindow (wnd, SW_MINIMIZE); $ ShowWindow (wnd, SW_RESTORE); } $ if (mode & 0x08) { $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0); $ AttachThreadInput (GetCurrentThreadId(), focus, true); $ SetForegroundWindow (wnd); $ AttachThreadInput (GetCurrentThreadId(), focus, false); } $ if (mode & 0x04) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } $ if (mode & 0x02) { $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS); } $ if (mode & 0x01) { $ UpdateWindow (wnd); } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ Internal TXLib window functions (_txCanvas...) //! @name Внутренние функции окна TXLib (_txCanvas...) //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned WINAPI _txCanvas_ThreadProc (void* data) { #define SetClassLong_ SetClassLongPtr #define GCL_HICON_ GCLP_HICON #define GCL_HICONSM_ GCLP_HICONSM #define GCL_HCURSOR_ GCLP_HCURSOR $8 _txCanvas_ThreadId = GetCurrentThreadId(); $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601 $ unsigned long stackSize = _TX_STACKSIZE; $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize)); $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data); $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0; $ HICON icon32 = LoadIcon (NULL, "_TX_ICON"); $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM"); $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR"); $ HMENU menu = LoadMenu (NULL, "_TX_MENU"); $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS"); $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107 if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); } $ Win32::GdiSetBatchLimit (1); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n")); $ _txActivateWindow (wnd, 0x10); $ ShowWindow (wnd, SW_SHOW); $ UpdateWindow (wnd); $ _txRunning = true; $ MSG msg = {}; $ while (GetMessage (&msg, NULL, 0, 0)) { if (!msg.hwnd) {$ continue; } if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; } $ TranslateMessage (&msg); $ DispatchMessage (&msg); $ Sleep (0); } $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak. $ LeaveCriticalSection (&_txCanvas_LockBackBuf); _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n")); $ if (_txWatchdogTimeout >= 0) {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); } $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running. { // No chances for good termination, so use exit(). $ _txCleanup(); $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014 } $ _txCanvas_ThreadId = 0; $ return true; //-V601 #undef SetClassLong #undef GCL_HICON_ #undef GCL_HICONSM_ #undef GCL_HCURSOR_ } //----------------------------------------------------------------------------------------------------------------- HWND _txCanvas_CreateWindow (const SIZE* sizePtr) { $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL; $ bool centered = false; if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; } $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false); $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top }; $ RECT conPos = {}; $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ()); if (console) {$ GetWindowRect (console, &conPos); } $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0); $ if (!wndClass) return (HWND) NULL; $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN, (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT, (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT, size.cx, size.cy, NULL, NULL, NULL, NULL); $ if (!wnd || !txWindow()) {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; } $ HMENU menu = GetSystemMenu (txWindow(), false); if (!menu) {$ return txWindow(); } $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted; $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted; $ return txWindow(); } //----------------------------------------------------------------------------------------------------------------- const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra) { $8 assert (classId); $ assert (wndProc); $ static char name[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ " _TX_VERSION " " __FILE__ " WndClass %08lX " "-------------[%s]-[TXLib]---*/", classId, (unsigned long) GetTickCount(), classId); $ WNDCLASS wc = { sizeof (wc) }; $ wc.lpszClassName = name; $ wc.lpfnWndProc = wndProc; $ wc.style = style; $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long); $ wc.hCursor = LoadCursor (NULL, IDC_ARROW); $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush); $ ATOM atom = RegisterClass (&wc); if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; } $ return (const char*)(uintptr_t) atom; } //----------------------------------------------------------------------------------------------------------------- int _txCanvas_SetRefreshLock (int count) { $8 int oldCount = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = count; $ HWND wnd = txWindow(); $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ return oldCount; } //----------------------------------------------------------------------------------------------------------------- HICON _txCreateTXIcon (int size) { $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560 $ const unsigned char image32 [32*32+1] = "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0" "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0" "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0" "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0" "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0" "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0" "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0" "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000"; $ const unsigned char image16 [16*16+1] = "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990" "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000"; $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0, 0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff }; $ const unsigned char* image = (size == 32)? image32 : image16; //-V112 $ POINT sz = { size, size }; $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask); $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor); $ for (int i = 0; i < size*size; i++) { assert (In (std::nomeow, image[i], '0', '9') || In (std::nomeow, image[i], 'A', 'F')); Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']); } $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP), (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) }; $ HICON icon = CreateIconIndirect (&info); $ assert (icon); $ _txBuffer_Delete (&dcMask) asserted; $ _txBuffer_Delete (&dcColor) asserted; $ return icon; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline bool _txCanvas_OK() { return _txCanvas_ThreadId && _txCanvas_Window && _txCanvas_BackBuf[0] && _txCanvas_BackBuf[1] && _txCanvas_Pixels; } //} //================================================================================================================= //================================================================================================================= //{ Main window event handlers (_txCanvas_On...) //! @name События основного окна (_txCanvas_On...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { #if defined (_TX_ALLOW_TRACE) int inTX = _txLoc::Cur.inTX++; if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)", 2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar); _txLoc::Cur.inTX = inTX; #endif $8 if (msg == WM_KEYDOWN && wpar == VK_F12 && GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU)) { $ _txCanvas_OnCmdABOUT (wnd, wpar); $ return DefWindowProc (wnd, msg, wpar, lpar); } WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread if (altWndProc) { $ LRESULT res = altWndProc (wnd, msg, wpar, lpar); $ if (res) return res; } static bool bkErased = false; switch (msg) { case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; } case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; } case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; } case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; } case WM_SIZE: {$ bkErased = false; break; } case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; } case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; } case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; } case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; } case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; } case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; } case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; } case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; } case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; } case WM_NULL: {$ return 0; } default: break; //-V2522 } if (msg == WM_SYSCOMMAND) switch (wpar) { case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; } case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; } default: break; //-V2522 } $ return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATE (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]); $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]); $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0; $ assert (_txCanvas_RefreshTimer); $ _txCanvas_UserDCs = new ::std::vector <HDC>; $ _txCanvas_Window = wnd; $ txSetDefaults(); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROY (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку); break; }
9227 
9228  if (canvas && !SendMessageTimeout (canvas, WM_NULL, 0,0, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL))
9229  {$ _txTrace (__FILE__, __LINE__, NULL, "WARNING: Программа не отвечает"); break; }
9230 
9231  if (!wine && !(i % 100500))
9232  {$ fprintf (stderr, "\r" "[Так нажмите же какую-нибудь клавишу...] \b\b"); }
9233  }
9234 
9235  if (istty0) {$ while (!wine && _kbhit()) ch = _getch(); }
9236 
9237 $ _txSetWindowText (wnd, NULL);
9238 
9239 $ fprintf (stderr, "\n");
9240 
9241  if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); }
9242 
9243 $ SetConsoleOutputCP (oldCP);
9244 $ txSetConsoleAttr (attr);
9245 
9246 $ return ch;
9247  }
9248 
9249 //-----------------------------------------------------------------------------------------------------------------
9250 
9251 int _txGetInput()
9252  {
9253 $4 HANDLE con = GetStdHandle (STD_INPUT_HANDLE);
9254 $ int ch = EOF;
9255 
9256 $ DWORD nChars = 0;
9257 $ if (GetConsoleMode (con, &nChars) == 0 &&
9258  PeekNamedPipe (con, NULL, 0, NULL, &nChars, NULL))
9259  {
9260 $ ch = (nChars)? fgetc (stdin) : EOF;
9261  }
9262 
9263  else if (_kbhit())
9264  {
9265 $ ch = _getch();
9266  }
9267 
9268 #if defined (_MSC_VER) && (_MSC_VER < 1700)
9269 
9270  else if (fseek (stdin, 1, SEEK_CUR) != EOF)
9271  {
9272 $ (void) fseek (stdin, -1, SEEK_CUR);
9273 $ ch = fgetc (stdin); // This causes blocking in MSVC 2011 beta
9274  }
9275 
9276 #endif
9277 
9278  if (ch == 3 /* Ctrl+C */) {$ raise (SIGABRT); }
9279 
9280 $ return ch;
9281  }
9282 
9283 //-----------------------------------------------------------------------------------------------------------------
9284 
9285 bool _txIsTTY (int fd)
9286  {
9287 $4 return GetFileType ((HANDLE)_get_osfhandle (fd)) == FILE_TYPE_CHAR;
9288  }
9289 
9290 //-----------------------------------------------------------------------------------------------------------------
9291 
9292 int _txSetWindowText (HWND wnd, const char* textRus, const char* textEng /*= NULL*/,
9293  int checkOfs /*= 0*/, const wchar_t checkLetters[2] /*= NULL*/)
9294  {
9295  struct tools
9296  {
9297  static LRESULT getWindowText (HWND window, wchar_t text[], size_t size)
9298  {
9299 $3 memset (text, 0, size * sizeof (*text));
9300 
9301 $ return SendMessageTimeoutW (window, WM_GETTEXT, (WPARAM) size, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL);
9302  }
9303 
9304  static LRESULT setWindowText (HWND window, wchar_t text[])
9305  {
9306 $1 return SendMessageTimeoutW (window, WM_SETTEXT, 0, (LPARAM) text, SMTO_BLOCK | SMTO_ABORTIFHUNG, _TX_TIMEOUT, NULL);
9307  }
9308  };
9309 
9310 $1 static wchar_t _tx_thread title [_TX_BUFSIZE+15] = L"TXLib";
9311 $ static wchar_t _tx_thread oldTitle [_TX_BUFSIZE+15] = L"TXLib";
9312 
9313 $ if (!textRus)
9314  {
9315 $ tools::setWindowText (wnd, oldTitle);
9316 $ return -1;
9317  }
9318 
9319 $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1);
9320 $ int len = (int) wcslen (title); if (len >= (int)_TX_BUFSIZE) len = _TX_BUFSIZE-1;
9321 $ memcpy (oldTitle, title, sizeof (oldTitle));
9322 
9323 $ if (textRus)
9324  {
9325 $ MultiByteToWideChar (_TX_CODEPAGE, 0, textRus, -1, title + len, (int)_TX_BUFSIZE - len);
9326 
9327 $ tools::setWindowText (wnd, title);
9328 $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1);
9329  if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[0]) {$ return 0; }
9330  if (!checkLetters) {$ return -2; }
9331  }
9332 
9333 $ if (textEng)
9334  {
9335 $ MultiByteToWideChar (_TX_CODEPAGE, 0, textEng, -1, title + len, (int)_TX_BUFSIZE - len);
9336 
9337 $ tools::setWindowText (wnd, title);
9338 $ tools::getWindowText (wnd, title, _TX_BUFSIZE-1);
9339  if (checkLetters && len <= (int)_TX_BUFSIZE-1-2 && title [len + checkOfs] == checkLetters[1]) {$ return 1; }
9340  if (!checkLetters) {$ return -2; }
9341  }
9342 
9343 $ return -3;
9344  }
9345 
9346 //-----------------------------------------------------------------------------------------------------------------
9347 
9348 int _txIsParentWaitable (DWORD* parentPID /*= NULL*/)
9349  {
9350 $4 PROCESSENTRY32* info = _txFindProcess();
9351 $ if (!info) return 0;
9352 
9353 $ info = _txFindProcess (info->th32ParentProcessID);
9354 $ if (!info) return 0;
9355 
9356 $ char parent [MAX_PATH] = "";
9357 $ strncpy_s (parent, sizeof (parent), info->szExeFile, sizeof (parent) - 1);
9358 $ if (parentPID) *parentPID = info->th32ProcessID;
9359 
9360 $ info = _txFindProcess (info->th32ParentProcessID); // info: grandparent
9361 
9362 $ char list[_TX_BUFSIZE] = _TX_WAITABLE_PARENTS;
9363 $ char* ctx = NULL;
9364 
9365 $ for (char* p = strtok_s (list, ", ", &ctx); p; p = strtok_s (NULL, ", ", &ctx))
9366  {
9367 $ char* gp = strchr (p, ':');
9368 
9369 $ if (gp)
9370  {
9371 $ *gp++ = 0;
9372 
9373 $ if (_stricmp (p, parent) != 0) { continue; }
9374 
9375 $ if (info) if (_stricmp (gp, info->szExeFile) == 0) // Was &&, but MSVC /analyze is so paranoid
9376  {$ return islower ((unsigned char) *gp)? +1 : -1; }
9377  }
9378  else
9379  {
9380 $ if (_stricmp (p, parent) == 0)
9381  {$ return islower ((unsigned char) *p)? +1 : -1; }
9382  }
9383  }
9384 
9385 $ return 0;
9386  }
9387 
9388 //-----------------------------------------------------------------------------------------------------------------
9389 
9390 void _txWatchdogTerminator (void* timeout) // Or Watchcat? Possibly will change in future versions
9391  {
9392 $3 if (_TX_ARGUMENT_FAILED (timeout)) return;
9393 
9394 $ Sleep (*(int*) timeout); //-V206
9395 
9396 $ OutputDebugString ("\n");
9397  txOutputDebugPrintf ("%s - WARNING: %s(): Timeout (%d) expired, activating. %s\n", // Kinda static reflection...
9398  _TX_VERSION, __func__, *(int*) timeout, ((__func__[8] == 'd')? "Bark, bark" : "Meow, meow")); //-V206
9399 $ DWORD parent = 0;
9400 $ if (_txIsParentWaitable (&parent))
9401  {
9402  txOutputDebugPrintf ("%s - WARNING: %s(): Calling _txKillProcess (0x%04lu)\n",
9403  _TX_VERSION, __func__, (unsigned long) parent);
9404 
9405 $ _txKillProcess (parent);
9406 
9407 $ HWND console = GetConsoleWindow();
9408 $ PostMessage (console, WM_KEYDOWN, VK_RETURN, 0x001C0001); // Scancode = 0x1C, Count = 1
9409 $ PostMessage (console, WM_KEYUP, VK_RETURN, 0xC01C0001); // Scancode = 0x1C, Count = 1, Prev = 1, Trans = 1
9410  }
9411 
9412  txOutputDebugPrintf ("%s - WARNING: %s(): Calling Win32::TerminateProcess (EXIT_FAILURE)\n", _TX_VERSION, __func__);
9413 $ Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE);
9414  }
9415 
9416 #endif // TX_COMPILED
9417 
9418 //}
9419 //-----------------------------------------------------------------------------------------------------------------
9420 
9421 //-----------------------------------------------------------------------------------------------------------------
9422 //{ Tools
9423 //-----------------------------------------------------------------------------------------------------------------
9424 
9425 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
9426 
9427 // You are here, little hacker?
9428 
9429 int _txTaskKill (const char i[] /*= NULL*/,
9430  const char doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine[] /*= NULL*/,
9431  unsigned x /*= 0*/)
9432  {
9433  // ...so tired of it already...
9434 
9435  #define name i // Great name!
9436  #define cmdLineSubstr doYouWantToFindSomethingInTheCommandLineIDidSomethingForYouToFindSomethingInTheCommandLineMaybeYouWillFindSomeInterestingInTheCommandLineSoIDidSomethingForYouInTheCommandLine
9437  #define pid x // Another great name, isn't it?
9438 
9439 $3 if (_TX_ARGUMENT_FAILED ((name || cmdLineSubstr || pid) && "Вот такие тут интересные имена встречаются...")) return false; //-V560 //-V601
9440 
9441 $ wchar_t cmdLineSubstrW[_TX_BUFSIZE] = L"";
9442  if (cmdLineSubstr) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, cmdLineSubstr, -1, cmdLineSubstrW, sizearr (cmdLineSubstrW)); }
9443 
9444 $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
9445 $ assert (sshot); if (!sshot) return 0; //-V547
9446 
9447 $ int killed = 0;
9448 
9449 $ PROCESSENTRY32 info = { sizeof (info) };
9450 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info))
9451  {
9452  bool kill = false;
9453 
9454  if (!kill && pid && info.th32ParentProcessID == pid) {$ kill = true; } //-V560
9455 
9456  if (!kill && name && _stricmp (info.szExeFile, name) == 0) {$ kill = true; }
9457 
9458  if (!kill)
9459  {
9460  wchar_t cmdLineW[_TX_BUFSIZE] = L"";
9461  if (!_txGetCommandLine (cmdLineW, sizearr (cmdLineW), info.th32ProcessID)) { continue; }
9462 
9463  if (*cmdLineW && stristrw (cmdLineW, cmdLineSubstrW)) {$ kill = true; }
9464  }
9465 
9466  if (kill)
9467  {
9468 $ if (_txKillProcess (info.th32ProcessID))
9469  {$ killed++; }
9470  }
9471  }
9472 
9473 $ CloseHandle (sshot);
9474 
9475 $ return killed;
9476 
9477  #undef name
9478  #undef cmdLine
9479  #undef pid
9480  }
9481 
9482 //-----------------------------------------------------------------------------------------------------------------
9483 
9484 bool _txKillProcess (DWORD pid)
9485  {
9486 $3 if (_TX_ARGUMENT_FAILED (pid)) return false;
9487 
9488 $ HANDLE token = INVALID_HANDLE_VALUE;
9489 $ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) asserted;
9490 
9491 $ LUID luid = {};
9492 $ LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid) asserted;
9493 
9494 $ TOKEN_PRIVILEGES priv = { 1, {{{ luid.LowPart, luid.HighPart}, SE_PRIVILEGE_ENABLED }}};
9495 $ TOKEN_PRIVILEGES old = {};
9496 
9497 $ DWORD oldSz = 0;
9498 $ AdjustTokenPrivileges (token, false, &priv, sizeof (priv), &old, &oldSz) asserted;
9499 
9500 $ HANDLE proc = OpenProcess (PROCESS_ALL_ACCESS, 0, pid);
9501 $ if (!proc) return false;
9502 
9503 $ bool ok = !!Win32::TerminateProcess (proc, 0);
9504 $ CloseHandle (proc);
9505 
9506 $ return ok;
9507  }
9508 
9509 //-----------------------------------------------------------------------------------------------------------------
9510 
9511 PROCESSENTRY32* _txFindProcess (unsigned pid /*= GetCurrentProcessId()*/)
9512  {
9513 $4 static PROCESSENTRY32 info = { sizeof (info) };
9514 $ if (!pid) return &info;
9515 
9516 $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
9517 $ assert (sshot); if (!sshot) return NULL; //-V547
9518 
9519 $ for (bool ok = !!Process32First (sshot, &info); ok; ok = !!Process32Next (sshot, &info))
9520  if (info.th32ProcessID == pid) break;
9521 
9522 $ CloseHandle (sshot);
9523 
9524 $ return &info;
9525  }
9526 
9527 //-----------------------------------------------------------------------------------------------------------------
9528 
9529 bool _txGetCommandLine (wchar_t cmdLine[], size_t szCmdLine, unsigned pid /*= _getpid()*/)
9530  {
9531 $6 if (_TX_ARGUMENT_FAILED (cmdLine)) return false;
9532 $ if (_TX_ARGUMENT_FAILED (szCmdLine >= 2)) return false; //-V547
9533 
9534 $ if (pid == (unsigned) _getpid())
9535  {
9536 $ wcsncpy_s (cmdLine, szCmdLine, GetCommandLineW(), szCmdLine-1);
9537 $ return true;
9538  }
9539 
9540 $ HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid);
9541  if (!proc) {$ return false; }
9542 
9543 $ Win32::PROCESS_BASIC_INFORMATION pbi = {};
9544 $ bool ok = (Win32::NtQueryInformationProcess (proc, 0 /*ProcessBasicInformation*/, &pbi, sizeof (pbi), NULL) == 0);
9545 
9546  // Should use ReadProcessMemory() because the info is actually in another address space
9547 
9548 $ Win32::PEB peb = {};
9549  if (ok && pbi.PebBaseAddress) {$ ok &= !!ReadProcessMemory (proc, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); }
9550 
9551 $ Win32::RTL_USER_PROCESS_PARAMETERS params = {};
9552  if (ok && peb.ProcessParameters) {$ ok &= !!ReadProcessMemory (proc, peb.ProcessParameters, &params, sizeof (params), NULL); }
9553 
9554 $ *cmdLine = 0;
9555  if (ok && params.CommandLine.Buffer) {$ ok &= !!ReadProcessMemory (proc, params.CommandLine.Buffer, cmdLine, //-V106
9556  MIN (params.CommandLine.Length + 2, (int) (szCmdLine * sizeof (*cmdLine)) - 2), //-V202
9557  NULL); }
9558 $ CloseHandle (proc) asserted;
9559 
9560 $ return ok;
9561  }
9562 
9563 //-----------------------------------------------------------------------------------------------------------------
9564 
9565 #define RVA_(type, module, addr) ( (type) ((uintptr_t) (module) + (uintptr_t) (addr)) )
9566 
9567 IMAGE_NT_HEADERS* _txGetNtHeaders (HMODULE module /*= GetModuleHandle (NULL)*/)
9568  {
9569 $4 assert (module);
9570 
9571 $ IMAGE_DOS_HEADER* dosHdr = RVA_ (IMAGE_DOS_HEADER*, module, 0);
9572 $ IMAGE_NT_HEADERS* ntHdr = RVA_ (IMAGE_NT_HEADERS*, module, dosHdr->e_lfanew);
9573 
9574 $ return (dosHdr->e_magic == IMAGE_DOS_SIGNATURE &&
9575  ntHdr->Signature == IMAGE_NT_SIGNATURE)? ntHdr : NULL;
9576  }
9577 
9578 //-----------------------------------------------------------------------------------------------------------------
9579 
9580 // TXLib continues to hack the reality to make your life better, sweeter and easier
9581 
9582 uintptr_t _txSetProcAddress (const char funcName[], uintptr_t newFunc, const char dllName[] /*= NULL*/, int useHotPatching /*= false*/,
9583  HMODULE module /*= NULL*/, bool debug /*= false*/)
9584  {
9585 $4 if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p):\n", funcName, (void*) newFunc, dllName, (void*) module);
9586 
9587 $ if (_TX_ARGUMENT_FAILED (funcName)) return 0;
9588 $ if (_TX_ARGUMENT_FAILED (newFunc)) return 0;
9589 
9590 $ if (!module) module = GetModuleHandle (NULL);
9591 $ if (!module) return 0;
9592 
9593 $ HMODULE dll = (dllName)? GetModuleHandle (dllName) : NULL;
9594 $ PROC oldFunc = (dll)? GetProcAddress (dll, funcName) : NULL;
9595 
9596 $ if (useHotPatching && oldFunc)
9597  {
9598 $ const size_t jmpSz = 1 + sizeof (DWORD); // sizeof (JMP rel instruction)
9599 
9600 $ DWORD oldRights = 0;
9601 $ if (!VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, PAGE_EXECUTE_READWRITE, &oldRights)) return 0;
9602 
9603  // Overwrite oldFunc prolog with JMP trampoline to newFunc.
9604  // Calling oldFunc from any location will lead to newFunc call anyway.
9605 
9606 $ *(BYTE*) ((char*)(uintptr_t) oldFunc + 0) = 0xE9; // JMP rel
9607 $ *(DWORD*) ((char*)(uintptr_t) oldFunc + 1) = ((char*)(uintptr_t) newFunc - (char*)(uintptr_t) oldFunc - jmpSz) & 0xFFFFFFFF; //-V206 //-V112 //-V2007 //-V104 //-V103
9608 
9609 $ FlushInstructionCache (GetCurrentProcess(), (void*)(uintptr_t) oldFunc, jmpSz);
9610 
9611 $ VirtualProtect ((void*)(uintptr_t) oldFunc, jmpSz, oldRights, &oldRights);
9612 
9613 $ return (uintptr_t) oldFunc;
9614  }
9615 
9616 // For PE structure and Import Table format, e.g. see https://books.google.ru/books?id=ifQPC86G66sC&pg=PA255
9617 // and below through Figure 5-5, and/or http://www.brokenthorn.com/Resources/OSDevPE.html.
9618 
9619 $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders (module);
9620  if (!ntHdr || (ntHdr ->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) {$ return 0; }
9621 
9622 $ DWORD impOffset = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
9623 $ IMAGE_IMPORT_DESCRIPTOR* desc = RVA_ (IMAGE_IMPORT_DESCRIPTOR*, module, impOffset);
9624 
9625 $ if (desc == (IMAGE_IMPORT_DESCRIPTOR*) ntHdr) return 0; //-V1027
9626 
9627 $ IMAGE_THUNK_DATA* thunk0 = NULL, * thunk1 = NULL;
9628 $ char* impDll = NULL;
9629 $ char* impName = NULL;
9630 $ void** impPtr = NULL;
9631 $ bool found = false;
9632 
9633  for (; desc->Name; desc++)
9634  {
9635 $ impDll = RVA_ (char*, module, desc->Name);
9636 $ if (dllName && _stricmp (impDll, dllName) != 0) continue;
9637 
9638 $ for (thunk0 = RVA_ (IMAGE_THUNK_DATA*, module, desc->OriginalFirstThunk),
9639  thunk1 = RVA_ (IMAGE_THUNK_DATA*, module, desc->FirstThunk);
9640 
9641  thunk0 && thunk1 && thunk1->u1.Function;
9642 
9643  thunk0++,
9644  thunk1++)
9645  {
9646  impName = (char*) RVA_ (IMAGE_IMPORT_BY_NAME*, module, thunk0->u1.AddressOfData) -> Name;
9647  impPtr = (void**)(uintptr_t) &thunk1->u1.Function; // Should change it, so this is ptr
9648 
9649  if (IsBadReadPtr (impName, sizeof (impName))) impName = NULL;
9650 
9651  if (debug) txOutputDebugPrintf ("[0x%p] %s!%s\n", *impPtr, impDll, impName);
9652 
9653  if ((oldFunc && (uintptr_t) oldFunc == (uintptr_t) *impPtr) ||
9654  (impName && _stricmp (funcName, impName) == 0)) //-V560
9655  {
9656  found = true;
9657  break;
9658  }
9659  }
9660 
9661 $ if (found) break;
9662  }
9663 
9664  if (debug) txOutputDebugPrintf ("_txSetProcAddress (%s, 0x%p, %s, 0x%p): %s\n\n",
9665  funcName, (void*) newFunc, dllName, (void*) module, (found? "FOUND" : "NOT found"));
9666 $ if (!found) return 0;
9667 
9668 $ DWORD rights = PAGE_READWRITE;
9669 $ if (!VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights)) return 0;
9670 
9671 $ *(uintptr_t*) impPtr = newFunc;
9672 
9673 $ VirtualProtect (impPtr, sizeof (*impPtr), rights, &rights);
9674 
9675 $ return (uintptr_t) oldFunc;
9676  }
9677 
9678 #undef RVA_
9679 
9680 //-----------------------------------------------------------------------------------------------------------------
9681 
9682 bool _txInDll()
9683  {
9684 $4 MODULEENTRY32 mod = { sizeof (mod) };
9685 
9686 $ HANDLE sshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
9687 $ assert (sshot); if (!sshot) return false; //-V547
9688 
9689 $ bool inDll = false;
9690 
9691 $ for (bool ok = !!Module32First (sshot, &mod); ok; ok = !!Module32Next (sshot, &mod))
9692  {
9693 $ if (!mod.modBaseAddr) continue;
9694 
9695 $ IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders ((HMODULE) mod.modBaseAddr);
9696 
9697 $ inDll = ntHdr && ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0);
9698 
9699 $ if (In (std::nomeow, (BYTE*)(uintptr_t)_txInDll, mod.modBaseAddr, mod.modBaseAddr + mod.modBaseSize)) //-V104
9700  {$ break; }
9701  }
9702 
9703 $ CloseHandle (sshot);
9704 $ return inDll;
9705  }
9706 
9707 //-----------------------------------------------------------------------------------------------------------------
9708 
9709 bool _txIsConsoleSubsystem()
9710  {
9711 $4 IMAGE_NT_HEADERS* ntHdr = _txGetNtHeaders();
9712 
9713 $ return ntHdr &&
9714  ntHdr ->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC &&
9715 
9716  (ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI ||
9717  ntHdr ->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI);
9718  }
9719 
9720 //-----------------------------------------------------------------------------------------------------------------
9721 
9722 bool _txIsBadReadPtr (const void* address)
9723  {
9724  MEMORY_BASIC_INFORMATION mbi = {};
9725  if (!VirtualQuery (address, &mbi, sizeof (mbi))) return true;
9726 
9727  if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) return true; // Guard page -> bad ptr
9728 
9729  DWORD readRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
9730 
9731  return !(mbi.Protect & readRights);
9732  }
9733 
9734 //-----------------------------------------------------------------------------------------------------------------
9735 
9736 void _txActivateWindow (HWND wnd, unsigned mode)
9737  {
9738 $1 EnableWindow (wnd, true);
9739 
9740 $ if (mode & 0x10)
9741  {
9742 $ ShowWindow (wnd, SW_MINIMIZE);
9743 $ ShowWindow (wnd, SW_RESTORE);
9744  }
9745 
9746 $ if (mode & 0x08)
9747  {
9748 $ int focus = GetWindowThreadProcessId (GetForegroundWindow(), 0);
9749 
9750 $ AttachThreadInput (GetCurrentThreadId(), focus, true);
9751 $ SetForegroundWindow (wnd);
9752 $ AttachThreadInput (GetCurrentThreadId(), focus, false);
9753  }
9754 
9755 $ if (mode & 0x04)
9756  {
9757 $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
9758  }
9759 
9760 $ if (mode & 0x02)
9761  {
9762 $ SetWindowPos (wnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS);
9763  }
9764 
9765 $ if (mode & 0x01)
9766  {
9767 $ UpdateWindow (wnd);
9768  }
9769  }
9770 
9771 #endif // TX_COMPILED
9772 
9773 //}
9774 //-----------------------------------------------------------------------------------------------------------------
9775 
9777 //}
9778 //=================================================================================================================
9779 
9780 //=================================================================================================================
9781 //{ Internal TXLib window functions (_txCanvas...)
9783 //=================================================================================================================
9784 
9785 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
9786 
9787 unsigned WINAPI _txCanvas_ThreadProc (void* data)
9788  {
9789  #define SetClassLong_ SetClassLongPtr
9790  #define GCL_HICON_ GCLP_HICON
9791  #define GCL_HICONSM_ GCLP_HICONSM
9792  #define GCL_HCURSOR_ GCLP_HCURSOR
9793 
9794 $8 _txCanvas_ThreadId = GetCurrentThreadId();
9795 
9796 $ if (_TX_ARGUMENT_FAILED (data)) return false; //-V601
9797 
9798 $ unsigned long stackSize = _TX_STACKSIZE;
9799 $ _TX_CALL (Win32::SetThreadStackGuarantee, (&stackSize));
9800 
9801 $ HWND wnd = _txCanvas_CreateWindow ((SIZE*) data);
9802 $ if (!txWindow()) return TX_DEBUG_ERROR ("\a" "Cannot create canvas!"), 0;
9803 
9804 $ HICON icon32 = LoadIcon (NULL, "_TX_ICON");
9805 $ HICON icon16 = LoadIcon (NULL, "_TX_ICONSM");
9806 $ HCURSOR cursor = LoadCursor (NULL, "_TX_CURSOR");
9807 $ HMENU menu = LoadMenu (NULL, "_TX_MENU");
9808 $ HACCEL accel = LoadAccelerators (NULL, "_TX_ACCELERATORS");
9809 
9810 $ SetClassLong_ (wnd, GCL_HICON_, (LONG_PTR) (icon32? icon32 : _txCreateTXIcon (32))); //-V107 //-V112
9811 $ SetClassLong_ (wnd, GCL_HICONSM_, (LONG_PTR) (icon16? icon16 : _txCreateTXIcon (16))); //-V107
9812 $ SetClassLong_ (wnd, GCL_HCURSOR_, (LONG_PTR) (cursor? cursor : LoadCursor (NULL, IDC_ARROW))); //-V107
9813 
9814  if (menu) {$ SetMenu (wnd, menu); DrawMenuBar (wnd); }
9815 
9816 $ Win32::GdiSetBatchLimit (1);
9817 
9818  _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STARTED: " _TX_MODULE "\n"));
9819 
9820 $ _txActivateWindow (wnd, 0x10);
9821 
9822 $ ShowWindow (wnd, SW_SHOW);
9823 $ UpdateWindow (wnd);
9824 
9825 $ _txRunning = true;
9826 
9827 $ MSG msg = {};
9828 $ while (GetMessage (&msg, NULL, 0, 0))
9829  {
9830  if (!msg.hwnd) {$ continue; }
9831 
9832  if (accel && TranslateAccelerator (wnd, accel, &msg)) {$ continue; }
9833 
9834 $ TranslateMessage (&msg);
9835 $ DispatchMessage (&msg);
9836 
9837 $ Sleep (0);
9838  }
9839 
9840 $ if (icon16) DestroyIcon (icon16); // If Explorer is displaying Tray Notification, these
9841 $ if (icon32) DestroyIcon (icon32); // calls will possibly fail, and we'll get resource leak.
9842 
9843 $ LeaveCriticalSection (&_txCanvas_LockBackBuf);
9844 
9845  _TX_ON_DEBUG (OutputDebugString (_TX_VERSION " - STOPPED: " _TX_MODULE "\n"));
9846 
9847 $ if (_txWatchdogTimeout >= 0)
9848  {$ Win32::_beginthread (_txWatchdogTerminator, 0, &_txWatchdogTimeout); }
9849 
9850 $ if (_txRunning && _txMain) // Main window is destroyed but main() is still running.
9851  { // No chances for good termination, so use exit().
9852 $ _txCleanup();
9853 $ ::exit ((int) msg.wParam); //-V202 //-V2509 //-V2014
9854  }
9855 
9856 $ _txCanvas_ThreadId = 0;
9857 $ return true; //-V601
9858 
9859  #undef SetClassLong
9860  #undef GCL_HICON_
9861  #undef GCL_HICONSM_
9862  #undef GCL_HCURSOR_
9863  }
9864 
9865 //-----------------------------------------------------------------------------------------------------------------
9866 
9867 HWND _txCanvas_CreateWindow (const SIZE* sizePtr)
9868  {
9869 $8 if (_TX_ARGUMENT_FAILED (sizePtr)) return NULL;
9870 
9871 $ bool centered = false;
9872  if (sizePtr->cx < 0 && sizePtr->cy < 0) {$ centered = true; }
9873 
9874 $ SIZE screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) };
9875 $ RECT rect = { 0, 0, abs (sizePtr->cx), abs (sizePtr->cy) }; AdjustWindowRect (&rect, _txWindowStyle, false);
9876 $ SIZE size = { rect.right - rect.left, rect.bottom - rect.top };
9877 $ RECT conPos = {};
9878 
9879 $ HWND console = _TX_CALL (Win32::GetConsoleWindow, ());
9880  if (console) {$ GetWindowRect (console, &conPos); }
9881 
9882 $ const char* wndClass = txRegisterClass ("MAIN", _txCanvas_WndProc, CS_HREDRAW | CS_VREDRAW | CS_OWNDC, BLACK_BRUSH, 0);
9883 $ if (!wndClass) return (HWND) NULL;
9884 
9885 $ HWND wnd = CreateWindowEx (WS_EX_APPWINDOW, wndClass, txGetModuleFileName (false), _txWindowStyle | WS_CLIPCHILDREN,
9886  (centered)? screen.cx/2 - size.cx/2 : (console)? conPos.left : CW_USEDEFAULT,
9887  (centered)? screen.cy/2 - size.cy/2 : (console)? conPos.top : CW_USEDEFAULT,
9888  size.cx, size.cy, NULL, NULL, NULL, NULL);
9889 $ if (!wnd || !txWindow())
9890  {$ return TX_DEBUG_ERROR ("Cannot create canvas: CreateWindowEx() failed"), (HWND) NULL; }
9891 
9892 $ HMENU menu = GetSystemMenu (txWindow(), false);
9893  if (!menu) {$ return txWindow(); }
9894 
9895 $ AppendMenu (menu, MF_SEPARATOR, 0, NULL) asserted;
9896 $ AppendMenu (menu, MF_STRING, _TX_IDM_CONSOLE, "Show &Console") asserted;
9897 $ AppendMenu (menu, MF_STRING, _TX_IDM_ABOUT, "&About...") asserted;
9898 
9899 $ return txWindow();
9900  }
9901 
9902 //-----------------------------------------------------------------------------------------------------------------
9903 
9904 const char* txRegisterClass (const char classId[], WNDPROC wndProc, unsigned style, int backBrush, int wndExtra)
9905  {
9906 $8 assert (classId);
9907 $ assert (wndProc);
9908 
9909 $ static char name[_TX_BUFSIZE] = "";
9910 $ _tx_snprintf_s (name, sizeof (name) - 1, "/*---[TXLib]-[%s]------------ "
9911  _TX_VERSION " " __FILE__ " WndClass %08lX "
9912  "-------------[%s]-[TXLib]---*/",
9913  classId, (unsigned long) GetTickCount(), classId);
9914 $ WNDCLASS wc = { sizeof (wc) };
9915 
9916 $ wc.lpszClassName = name;
9917 $ wc.lpfnWndProc = wndProc;
9918 $ wc.style = style;
9919 $ wc.cbWndExtra = (wndExtra + 1) * (int) sizeof (long);
9920 
9921 $ wc.hCursor = LoadCursor (NULL, IDC_ARROW);
9922 $ wc.hbrBackground = (HBRUSH) Win32::GetStockObject (backBrush);
9923 
9924 $ ATOM atom = RegisterClass (&wc);
9925  if (!atom) {$ TX_DEBUG_ERROR ("RegisterClass (\"%s\") failed", name); return 0; }
9926 
9927 $ return (const char*)(uintptr_t) atom;
9928  }
9929 
9930 //-----------------------------------------------------------------------------------------------------------------
9931 
9932 int _txCanvas_SetRefreshLock (int count)
9933  {
9934 $8 int oldCount = _txCanvas_RefreshLock;
9935 
9936 $ _txCanvas_RefreshLock = count;
9937 
9938 $ HWND wnd = txWindow();
9939 
9940 $ if ((_txCanvas_RefreshLock <= 0 || oldCount <= 0) && wnd)
9941  {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); }
9942 
9943 $ return oldCount;
9944  }
9945 
9946 //-----------------------------------------------------------------------------------------------------------------
9947 
9948 HICON _txCreateTXIcon (int size)
9949  {
9950 $8 if (_TX_ARGUMENT_FAILED (size == 32 || size == 16)) return NULL; //-V112 //-V560
9951 
9952 $ const unsigned char image32 [32*32+1] =
9953  "00000000000000000000000000000000""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""0F0000000000000000000000000000F0""0F0000000000000000000000000000F0"
9954  "0F0000000000000099999999999900F0""0F0000000000000090300333330900F0""0F0000000990000090000000000900F0""0F00000099990000900BB000000900F0"
9955  "0F0000039999000090B00090900900F0""0F0000009999000090B00999990900F0""0F00000009903799900BB090900900F0""0F000000009BB70090000010000900F0"
9956  "0F0000000B90000090000000000900F0""0F000000B0B0000099999999999900F0""0F00007B30B0000090000000000000F0""0F00007300B0000090000000000000F0"
9957  "0F00000000B3000090000000000000F0""0F0000000B0B000090000000000000F0""0F000000B303B00090000000000000F0""0F000003B000B00090000000000000F0"
9958  "0F00003B00003B0090000000000000F0""0F0000300000030090000000000000F0""0F0000000448888888888844000000F0""0F00004886E6E6E60E66E6EEEE4400F0"
9959  "0F4488866E0E60E00660E06E66EEE4F0""0F868806E06E06E666E66E00E06EE6F0""0F08606E66E0066000E006E66E00E6F0""0F8666E006600E00006600E006E00EF0"
9960  "0F000E066888888888888888606660F0""0F66EEE6EE000E00000E00086EEEE6F0""0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0""00000000000000000000000000000000";
9961 
9962 $ const unsigned char image16 [16*16+1] =
9963  "0000000000000000""0000000999999990""0009000900000090""0099900909973090""0059700909009390""0009799909973090""0099000900000090""0959330999999990"
9964  "0709500900000000""0095930900000000""0090393900000000""0790073900000000""0900000900000000""000EE6E6E6E6E000""0EE6E6E6E6E6EEE0""0000000000000000";
9965 
9966 $ const COLORREF pal['F'-'0'+1] = { 0x000000, 0x002b2b, 0x555500, 0x005555, 0x808000, 0x008080, 0xaaaa00, 0x00aaaa, 0xd5d500, 0x00d5d5, 0,0,0,0,0,0,0,
9967  0xffff00, 0x00ffff, 0xffffaa, 0xaaffff, 0xd5d500, 0xffffff };
9968 
9969 $ const unsigned char* image = (size == 32)? image32 : image16; //-V112
9970 
9971 $ POINT sz = { size, size };
9972 $ HDC dcMask = _txBuffer_Create (txWindow(), &sz); assert (dcMask);
9973 $ HDC dcColor = _txBuffer_Create (txWindow(), &sz); assert (dcColor);
9974 
9975 $ for (int i = 0; i < size*size; i++)
9976  {
9977  assert (In (std::nomeow, image[i], '0', '9') ||
9978  In (std::nomeow, image[i], 'A', 'F'));
9979 
9980  Win32::SetPixel (dcColor, i % size, i / size, pal [image[i] - '0']);
9981  }
9982 
9983 $ ICONINFO info = { true, 0, 0, (HBITMAP) Win32::GetCurrentObject (dcMask, OBJ_BITMAP),
9984  (HBITMAP) Win32::GetCurrentObject (dcColor, OBJ_BITMAP) };
9985 
9986 $ HICON icon = CreateIconIndirect (&info);
9987 $ assert (icon);
9988 
9989 $ _txBuffer_Delete (&dcMask) asserted;
9990 $ _txBuffer_Delete (&dcColor) asserted;
9991 
9992 $ return icon;
9993  }
9994 
9995 #endif // TX_COMPILED
9996 
9997 //-----------------------------------------------------------------------------------------------------------------
9998 
9999 inline bool _txCanvas_OK()
10000  {
10001  return _txCanvas_ThreadId &&
10002  _txCanvas_Window &&
10003  _txCanvas_BackBuf[0] &&
10004  _txCanvas_BackBuf[1] &&
10005  _txCanvas_Pixels;
10006  }
10007 
10008 //}
10009 //=================================================================================================================
10010 
10011 //=================================================================================================================
10012 //{ Main window event handlers (_txCanvas_On...)
10014 //=================================================================================================================
10016 
10017 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
10018 
10019 LRESULT CALLBACK _txCanvas_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar)
10020  {
10021 #if defined (_TX_ALLOW_TRACE)
10022 
10023  int inTX = _txLoc::Cur.inTX++;
10024 
10025  if (_txLoc::Cur.trace) _txTrace (__FILE__, __LINE__, __TX_FUNCTION__, "%*s" "0x%X <- 0x%04X (0x%08X, 0x%08lX)",
10026  2 * (_txLoc::Cur.inTX - 1), "", wnd, msg, wpar, lpar);
10027  _txLoc::Cur.inTX = inTX;
10028 
10029 #endif
10030 
10031 $8 if (msg == WM_KEYDOWN && wpar == VK_F12 &&
10032  GetKeyState (VK_SHIFT) && GetKeyState (VK_CONTROL) && GetKeyState (VK_MENU))
10033  {
10034 $ _txCanvas_OnCmdABOUT (wnd, wpar);
10035 $ return DefWindowProc (wnd, msg, wpar, lpar);
10036  }
10037 
10038  WNDPROC altWndProc = _txAltWndProc; // Cache to prevent change from main thread
10039  if (altWndProc)
10040  {
10041 $ LRESULT res = altWndProc (wnd, msg, wpar, lpar);
10042 $ if (res) return res;
10043  }
10044 
10045  static bool bkErased = false;
10046 
10047  switch (msg)
10048  {
10049  case WM_CREATE: {$ _txCanvas_OnCREATE (wnd); return 0; }
10050 
10051  case WM_CLOSE: {$ if (_txCanvas_OnCLOSE (wnd)) break; else return 0; }
10052  case WM_DESTROY: {$ _txCanvas_OnDESTROY (wnd); return 0; }
10053 
10054  case WM_ERASEBKGND: {$ if (!bkErased) { bkErased = true; break; } else return 1; }
10055  case WM_SIZE: {$ bkErased = false; break; }
10056 
10057  case WM_PAINT: {$ _txCanvas_OnPAINT (wnd); return 0; }
10058 
10059  case WM_TIMER: {$ _txCanvas_OnTIMER (wnd, wpar); return 0; }
10060 
10061  case WM_KEYUP: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, false)) return 0; else break; }
10062  case WM_KEYDOWN: {$ if (_txCanvas_OnKEY (wnd, wpar, lpar, true)) return 0; else break; }
10063  case WM_CHAR: {$ if (_txCanvas_OnCHAR (wnd, wpar, lpar)) return 0; else break; }
10064 
10065  case WM_LBUTTONUP:
10066  case WM_LBUTTONDOWN:
10067  case WM_RBUTTONUP:
10068  case WM_RBUTTONDOWN:
10069  case WM_MBUTTONUP:
10070  case WM_MBUTTONDOWN:
10071  case WM_MOUSEMOVE: {$ _txCanvas_OnMOUSEMOVE (wnd, wpar, lpar); return 0; }
10072 
10073  case WM_MOUSELEAVE: {$ _txCanvas_OnMOUSELEAVE (wnd); return 0; }
10074 
10075  case _TX_WM_CREATEWND: {$ _txCanvas_OnCREATEWND (wnd, wpar, lpar); return 0; }
10076  case _TX_WM_DESTROYWND: {$ _txCanvas_OnDESTROYWND (wnd, wpar, lpar); return 0; }
10077 
10078  case WM_NULL: {$ return 0; }
10079 
10080  default: break; //-V2522
10081  }
10082 
10083  if (msg == WM_SYSCOMMAND) switch (wpar)
10084  {
10085  case _TX_IDM_ABOUT: {$ _txCanvas_OnCmdABOUT (wnd, wpar); return 0; }
10086  case _TX_IDM_CONSOLE: {$ _txCanvas_OnCmdCONSOLE (wnd, wpar); return 0; }
10087 
10088  default: break; //-V2522
10089  }
10090 
10091 $ return DefWindowProc (wnd, msg, wpar, lpar);
10092  }
10093 
10094 //-----------------------------------------------------------------------------------------------------------------
10095 
10096 bool _txCanvas_OnCREATE (HWND wnd)
10097  {
10098 $8 if (_TX_ARGUMENT_FAILED (wnd)) return false;
10099 
10100 $ _txCanvas_BackBuf[0] = _txBuffer_Create (wnd, NULL, NULL, &_txCanvas_Pixels); assert (_txCanvas_BackBuf[0]);
10101 $ _txCanvas_BackBuf[1] = _txBuffer_Create (wnd, NULL, NULL, NULL); assert (_txCanvas_BackBuf[1]);
10102 
10103 $ if (!SetTimer (wnd, _txCanvas_RefreshTimer, _txWindowUpdateInterval, NULL)) _txCanvas_RefreshTimer = 0;
10104 $ assert (_txCanvas_RefreshTimer);
10105 
10106 $ _txCanvas_UserDCs = new ::std::vector <HDC>;
10107 
10108 $ _txCanvas_Window = wnd;
10109 
10110 $ txSetDefaults();
10111 
10112 $ return true;
10113  }
10114 
10115 //-----------------------------------------------------------------------------------------------------------------
10116 
10117 bool _txCanvas_OnDESTROY (HWND wnd)
10118  {
10119 $8 if (_TX_ARGUMENT_FAILED (wnd)) return false;
10120 
10121  // Инициируем остановку цикла сообщений $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS); $ if (!_txCanvas_Window) return false; // Indicate that we are about to manually terminate $ _txExit = true; // Lock GDI resources $ bool locked = false; $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT); $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources"); // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
10122 
10123 $ PostQuitMessage (_txRunning? WM_DESTROY : EXIT_SUCCESS);
10124 
10125 $ if (!_txCanvas_Window) return false;
10126 
10127  // Indicate that we are about to manually terminate
10128 
10129 $ _txExit = true;
10130 
10131  // Lock GDI resources
10132 
10133 $ bool locked = false;
10134 $ _txWaitFor ((locked = txLock (false), locked), _TX_TIMEOUT);
10135 $ if (!locked) TX_DEBUG_ERROR ("Cannot lock GDI to free resources");
10136 
10137  // Освобождаем пользовательские ресурсы $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty()) { $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202 $ Sleep (_TX_TIMEOUT); $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i)); $ _txCanvas_UserDCs->clear(); } // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
10138 
10139 $ if (_txCanvas_UserDCs && !_txCanvas_UserDCs->empty())
10140  {
10141 $ txNotifyIcon (NIIF_ERROR, NULL, "Вы забыли освободить %d HDC.", (int) _txCanvas_UserDCs->size()); //-V202
10142 $ Sleep (_TX_TIMEOUT);
10143 
10144 $ for (size_t i = 0; i < _txCanvas_UserDCs->size(); i++) _txBuffer_Delete (&_txCanvas_UserDCs->at (i));
10145 $ _txCanvas_UserDCs->clear();
10146  }
10147 
10148  // Освобождаем ресурсы, связанные с окном $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted; $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted; $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted; $ _txCanvas_Pixels = NULL; $ txUnlock(); // Indicate that we are destroyed $ _txCanvas_Window = NULL; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558 { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMain && _txRunning && txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n" "Лучше подождать, когда main() завершится - это отображается в заголовке окна.", txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnTIMER (HWND wnd, WPARAM) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false; $ InvalidateRect (wnd, NULL, false) asserted; $ UpdateWindow (wnd) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnPAINT (HWND wnd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT); $ PAINTSTRUCT ps = {}; $ HDC wndDc = BeginPaint (wnd, &ps); $ if (!wndDc) return false; $ HDC dc0 = _txCanvas_BackBuf[0], dc1 = _txCanvas_BackBuf[1]; $ RECT r = {}; $ GetClientRect (wnd, &r) asserted; $ POINT wndSize = { r.right - r.left, r.bottom - r.top }; $ POINT dcSize = txGetExtent (dc1); $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) && txLock (false)) { $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY); $ if (_txConsole >= 0) {$ _txConsole_Draw (dc1); } $ txUnlock(); } // Magic 100500 value is used to completely block screen refresh. // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL. // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers // themselves. // Yes guys, with all your software installed. :( $ if (_txCanvas_RefreshLock != 100500) { if (_txSwapBuffers) { $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y) { $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY); } else { $ Win32::SetStretchBltMode (wndDc, HALFTONE); $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY); } } $ EndPaint (wnd, &ps) asserted; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info) { $8 INPUT_RECORD evt[2] = {}; $ evt[0].EventType = KEY_EVENT; $ evt[0].Event.KeyEvent.bKeyDown = true; $ evt[0].Event.KeyEvent.wRepeatCount = 1; $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch); $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX $ evt[0].Event.KeyEvent.dwControlKeyState = 0; $ evt[1] = evt[0]; $ evt[1].Event.KeyEvent.bKeyDown = false; $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down) { $8 INPUT_RECORD evt = {}; $ evt.EventType = KEY_EVENT; $ evt.Event.KeyEvent.bKeyDown = down; $ evt.Event.KeyEvent.wRepeatCount = 1; $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16); $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk; $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0; $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job $ DWORD written = 0; $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ if (!_txCanvas_OK()) return false; $ if (_txMousePos.x == -1 && _txMousePos.y == -1) { $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT }; $ TrackMouseEvent (&track); } $ _txMousePos.x = LOWORD (coords); $ _txMousePos.y = HIWORD (coords); $ _txMouseButtons = (unsigned) buttons; //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnMOUSELEAVE (HWND) { $8 _txMousePos.x = -1; $ _txMousePos.y = -1; $ _txMouseButtons = 0; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar; $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style, create->x, create->y, create->cx, create->cy, create->hwndParent, create->hMenu, NULL, create->lpCreateParams); $ *(HWND*) create->hInstance = wnd; $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar) { $8 if (_TX_ARGUMENT_FAILED (lpar)) return false; $ DestroyWindow ((HWND) lpar); $ return false; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd) { $8 if (_TX_ARGUMENT_FAILED (wnd)) return false; $ HWND console = Win32::GetConsoleWindow(); $ if (!console) return false; $ bool visible = !!IsWindowVisible (console); $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE); $ visible = !!IsWindowVisible (console); $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202 $ return true; } //----------------------------------------------------------------------------------------------------------------- bool _txCanvas_OnCmdABOUT (HWND, WPARAM) { $8 //{ Overriding the missing names, if the set is uncomplete #if defined (__MODULE) #define ABOUT_NAME_ __MODULE #else #define ABOUT_NAME_ "TXLib" #endif #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) #ifndef __MODULE #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n" #endif #ifndef __VERSION #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n" #endif #ifndef __DESCRIPTION #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n" #endif #ifndef __AUTHOR #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name." #endif #endif //} $ static char text[_TX_BUFSIZE] = ""; $ _tx_snprintf_s (text, sizeof (text) - 1, "Application:\n\n" #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR) __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n" #else "Здесь могла бы быть Ваша реклама :)\n" "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n" #endif "\n" "%s", _txAppInfo()); $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION); // And a bit of HTTP-code in C++ function: goto http; http://sizeof.livejournal.com $ return true; #undef ABOUT_NAME_ } #endif // TX_COMPILED //! @} //} //================================================================================================================= //================================================================================================================= //{ Console-support functions (_txConsole...) //! @name Функции консольного окна (_txConsole...) //================================================================================================================= //! @{ #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< HWND _txConsole_Attach() { $1 HWND console = Win32::GetConsoleWindow(); $ if (!console) { $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem()); $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb(); $ assert (teb); $ assert (teb->ProcessEnvironmentBlock); $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters; $ assert (params); $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo() // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :( // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!.. { $ params->dwFlags |= STARTF_USESHOWWINDOW; $ params->wShowWindow = SW_MINIMIZE; } $ AllocConsole(); $ console = Win32::GetConsoleWindow(); } $ if (!console) return NULL; $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть. $ if (!_txIsConsoleSubsystem()) {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console $ return console; } //----------------------------------------------------------------------------------------------------------------- int txSetLocale (int codepage /*= _TX_CODEPAGE*/, const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/) { $1 int oldPage = GetConsoleOutputCP(); // Устанавливаем нужную кодовую страницу для консоли Windows $ if (codepage) { $ SetConsoleCP (codepage); $ SetConsoleOutputCP (codepage); } // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN - // обозначение кодовой страницы (например, для русского языка - CP1251). $ if (locale) { $ setlocale (LC_ALL, locale); $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers } #ifndef __CYGWIN__ $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility. $ if (wLocale && !wine) { $ _wsetlocale (LC_ALL, wLocale); $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above) } #endif (void) wLocale; $ return oldPage; } //----------------------------------------------------------------------------------------------------------------- void txReopenStdio() { $1 // Переоткрываем заново <s>Америку
10149 
10150 $ if (_txCanvas_RefreshTimer) KillTimer (wnd, _txCanvas_RefreshTimer) asserted;
10151 
10152 $ if (_txCanvas_BackBuf[1]) _txBuffer_Delete (&_txCanvas_BackBuf[1]) asserted;
10153 $ if (_txCanvas_BackBuf[0]) _txBuffer_Delete (&_txCanvas_BackBuf[0]) asserted;
10154 $ _txCanvas_Pixels = NULL;
10155 
10156 $ txUnlock();
10157 
10158  // Indicate that we are destroyed
10159 
10160 $ _txCanvas_Window = NULL;
10161 
10162 $ return true;
10163  }
10164 
10165 //-----------------------------------------------------------------------------------------------------------------
10166 
10167 bool _txCanvas_OnCLOSE (HWND wnd) //-V2009 //-V2558
10168  {
10169 $8 if (_TX_ARGUMENT_FAILED (wnd)) return false;
10170 $ if (!_txCanvas_OK()) return false;
10171 
10172 $ if (_txMain && _txRunning &&
10173  txMessageBox ("Функция main() не завершена. Программа все еще работает. Прервать аварийно?\n\n"
10174  "Лучше подождать, когда main() завершится - это отображается в заголовке окна.",
10175  txGetModuleFileName (false), MB_YESNOCANCEL | MB_ICONSTOP) != IDYES) return false;
10176 $ return true;
10177  }
10178 
10179 //-----------------------------------------------------------------------------------------------------------------
10180 
10181 bool _txCanvas_OnTIMER (HWND wnd, WPARAM)
10182  {
10183 $8 if (_TX_ARGUMENT_FAILED (wnd)) return false;
10184 
10185 $ if (_txCanvas_RefreshLock > 0 || !_txRunning) return false;
10186 
10187 $ InvalidateRect (wnd, NULL, false) asserted;
10188 $ UpdateWindow (wnd) asserted;
10189 
10190 $ return true;
10191  }
10192 
10193 //-----------------------------------------------------------------------------------------------------------------
10194 
10195 bool _txCanvas_OnPAINT (HWND wnd)
10196  {
10197 $8 if (_TX_ARGUMENT_FAILED (wnd)) return false;
10198 $ if (!_txCanvas_OK()) return false;
10199 
10200 $ bool forceRedraw = GetAsyncKeyState (VK_MENU) && GetAsyncKeyState (VK_CONTROL) &&
10201  GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_SNAPSHOT);
10202 
10203 $ PAINTSTRUCT ps = {};
10204 $ HDC wndDc = BeginPaint (wnd, &ps);
10205 $ if (!wndDc) return false;
10206 
10207 $ HDC dc0 = _txCanvas_BackBuf[0],
10208  dc1 = _txCanvas_BackBuf[1];
10209 
10210 $ RECT r = {};
10211 $ GetClientRect (wnd, &r) asserted;
10212 $ POINT wndSize = { r.right - r.left, r.bottom - r.top };
10213 
10214 $ POINT dcSize = txGetExtent (dc1);
10215 
10216 $ if ((_txCanvas_RefreshLock <= 0 || forceRedraw) &&
10217  txLock (false))
10218  {
10219 $ Win32::BitBlt (dc1, 0, 0, dcSize.x, dcSize.y, dc0, 0, 0, SRCCOPY);
10220 
10221 $ if (_txConsole >= 0)
10222  {$ _txConsole_Draw (dc1); }
10223 
10224 $ txUnlock();
10225  }
10226 
10227  // Magic 100500 value is used to completely block screen refresh.
10228  // Since no value can be 100500 or above, this condition is always true and the refresh cannot be blocked IRL.
10229  // Do not use 100501 because it may lead to errors on some compilers and possible may crash the compilers
10230  // themselves.
10231  // Yes guys, with all your software installed. :(
10232 
10233 $ if (_txCanvas_RefreshLock != 100500)
10234  {
10235  if (_txSwapBuffers)
10236  {
10237 $ _txSwapBuffers (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY);
10238  }
10239  else if (dcSize.x == wndSize.x && dcSize.y == wndSize.y)
10240  {
10241 $ Win32::BitBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, SRCCOPY);
10242  }
10243  else
10244  {
10245 $ Win32::SetStretchBltMode (wndDc, HALFTONE);
10246 $ Win32::StretchBlt (wndDc, 0, 0, wndSize.x, wndSize.y, dc1, 0, 0, dcSize.x, dcSize.y, SRCCOPY);
10247  }
10248  }
10249 
10250 $ EndPaint (wnd, &ps) asserted;
10251 
10252 $ return true;
10253  }
10254 
10255 //-----------------------------------------------------------------------------------------------------------------
10256 
10257 bool _txCanvas_OnCHAR (HWND, WPARAM ch, LPARAM info)
10258  {
10259 $8 INPUT_RECORD evt[2] = {};
10260 
10261 $ evt[0].EventType = KEY_EVENT;
10262 $ evt[0].Event.KeyEvent.bKeyDown = true;
10263 $ evt[0].Event.KeyEvent.wRepeatCount = 1;
10264 $ evt[0].Event.KeyEvent.uChar.AsciiChar = (char) (ch);
10265 $ evt[0].Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16);
10266 $ evt[0].Event.KeyEvent.wVirtualKeyCode = (WORD) MapVirtualKey ((WORD) (info >> 16), 3); // 3 == MAPVK_VSC_TO_VK_EX
10267 $ evt[0].Event.KeyEvent.dwControlKeyState = 0;
10268 
10269 $ evt[1] = evt[0];
10270 $ evt[1].Event.KeyEvent.bKeyDown = false;
10271 
10272 $ DWORD written = 0;
10273 $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), evt, 2, &written);
10274 
10275 $ return true;
10276  }
10277 
10278 //-----------------------------------------------------------------------------------------------------------------
10279 
10280 bool _txCanvas_OnKEY (HWND, WPARAM vk, LPARAM info, bool down)
10281  {
10282 $8 INPUT_RECORD evt = {};
10283 
10284 $ evt.EventType = KEY_EVENT;
10285 $ evt.Event.KeyEvent.bKeyDown = down;
10286 $ evt.Event.KeyEvent.wRepeatCount = 1;
10287 $ evt.Event.KeyEvent.uChar.AsciiChar = (char) MapVirtualKey ((WORD) vk, 2); // 2 == MAPVK_VK_TO_CHAR
10288 $ evt.Event.KeyEvent.wVirtualScanCode = (WORD) (info >> 16);
10289 $ evt.Event.KeyEvent.wVirtualKeyCode = (WORD) vk;
10290 $ evt.Event.KeyEvent.dwControlKeyState = (DWORD) (info & (1 << (24-1)))? ENHANCED_KEY : 0;
10291 
10292 $ if (evt.Event.KeyEvent.uChar.AsciiChar) return false; // Let TranslateMessage() and WM_CHAR do the job
10293 
10294 $ DWORD written = 0;
10295 $ WriteConsoleInput (GetStdHandle (STD_INPUT_HANDLE), &evt, 1, &written);
10296 
10297 $ return true;
10298  }
10299 
10300 //-----------------------------------------------------------------------------------------------------------------
10301 
10302 bool _txCanvas_OnMOUSEMOVE (HWND wnd, WPARAM buttons, LPARAM coords)
10303  {
10304 $8 if (_TX_ARGUMENT_FAILED (wnd)) return false;
10305 $ if (!_txCanvas_OK()) return false;
10306 
10307 $ if (_txMousePos.x == -1 && _txMousePos.y == -1)
10308  {
10309 $ TRACKMOUSEEVENT track = { sizeof (track), TME_HOVER | TME_LEAVE, wnd, HOVER_DEFAULT };
10310 $ TrackMouseEvent (&track);
10311  }
10312 
10313 $ _txMousePos.x = LOWORD (coords);
10314 $ _txMousePos.y = HIWORD (coords);
10315 $ _txMouseButtons = (unsigned) buttons; //-V202
10316 
10317 $ return true;
10318  }
10319 
10320 //-----------------------------------------------------------------------------------------------------------------
10321 
10322 bool _txCanvas_OnMOUSELEAVE (HWND)
10323  {
10324 $8 _txMousePos.x = -1;
10325 $ _txMousePos.y = -1;
10326 $ _txMouseButtons = 0;
10327 
10328 $ return true;
10329  }
10330 
10331 //-----------------------------------------------------------------------------------------------------------------
10332 
10333 bool _txCanvas_OnCREATEWND (HWND, WPARAM, LPARAM lpar)
10334  {
10335 $8 if (_TX_ARGUMENT_FAILED (lpar)) return false;
10336 
10337 $ const CREATESTRUCT* create = (CREATESTRUCT*) lpar;
10338 
10339 $ HWND wnd = CreateWindowEx (create->dwExStyle, create->lpszClass, create->lpszName, create->style,
10340  create->x, create->y, create->cx, create->cy,
10341  create->hwndParent, create->hMenu, NULL, create->lpCreateParams);
10342 
10343 $ *(HWND*) create->hInstance = wnd;
10344 
10345 $ return true;
10346  }
10347 
10348 //-----------------------------------------------------------------------------------------------------------------
10349 
10350 bool _txCanvas_OnDESTROYWND (HWND, WPARAM, LPARAM lpar)
10351  {
10352 $8 if (_TX_ARGUMENT_FAILED (lpar)) return false;
10353 
10354 $ DestroyWindow ((HWND) lpar);
10355 
10356 $ return false;
10357  }
10358 
10359 //-----------------------------------------------------------------------------------------------------------------
10360 
10361 bool _txCanvas_OnCmdCONSOLE (HWND wnd, WPARAM cmd)
10362  {
10363 $8 if (_TX_ARGUMENT_FAILED (wnd)) return false;
10364 
10365 $ HWND console = Win32::GetConsoleWindow();
10366 $ if (!console) return false;
10367 
10368 $ bool visible = !!IsWindowVisible (console);
10369 
10370 $ ShowWindow (console, visible? SW_HIDE : SW_RESTORE);
10371 
10372 $ visible = !!IsWindowVisible (console);
10373 $ CheckMenuItem (GetSystemMenu (wnd, false), (int) cmd, visible? MF_CHECKED : MF_UNCHECKED); //-V202
10374 
10375 $ return true;
10376  }
10377 
10378 //-----------------------------------------------------------------------------------------------------------------
10379 
10380 bool _txCanvas_OnCmdABOUT (HWND, WPARAM)
10381  {
10382 $8 //{ Overriding the missing names, if the set is uncomplete
10383 
10384  #if defined (__MODULE)
10385  #define ABOUT_NAME_ __MODULE
10386  #else
10387  #define ABOUT_NAME_ "TXLib"
10388  #endif
10389 
10390  #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR)
10391 
10392  #ifndef __MODULE
10393  #define __MODULE "TXLib" "\n" "#define __MODULE to set the name.\n"
10394  #endif
10395 
10396  #ifndef __VERSION
10397  #define __VERSION "(0.000000000)." "\n" "#define __VERSION to set the string value.\n"
10398  #endif
10399 
10400  #ifndef __DESCRIPTION
10401  #define __DESCRIPTION "(Да, мне лень задать описание)." "\n" "#define __DESCRIPTION to override project role.\n"
10402  #endif
10403 
10404  #ifndef __AUTHOR
10405  #define __AUTHOR "(Непонятно кто)." "\n" "#define __AUTHOR to override this name."
10406  #endif
10407 
10408  #endif
10409  //}
10410 
10411 $ static char text[_TX_BUFSIZE] = "";
10412 
10413 $ _tx_snprintf_s (text, sizeof (text) - 1,
10414 
10415  "Application:\n\n"
10416 
10417  #if defined (__MODULE) || defined (__VERSION) || defined (__DESCRIPTION) || defined (__AUTHOR)
10418  __MODULE " version " __VERSION "\n" __DESCRIPTION "\n" "Copyright (c) " __AUTHOR "\n"
10419  #else
10420  "Здесь могла бы быть Ваша реклама :)\n"
10421  "#define __MODULE to \"your program name\" before including TXLib.h to use this billboard...\n"
10422  #endif
10423 
10424  "\n" "%s", _txAppInfo());
10425 
10426 $ txMessageBox (text, "About " ABOUT_NAME_, MB_ICONINFORMATION);
10427 
10428  // And a bit of HTTP-code in C++ function:
10429 
10430  goto http;
10431  http://sizeof.livejournal.com
10432 
10433 $ return true;
10434 
10435  #undef ABOUT_NAME_
10436  }
10437 
10438 #endif // TX_COMPILED
10439 
10441 //}
10442 //=================================================================================================================
10443 
10444 //=================================================================================================================
10445 //{ Console-support functions (_txConsole...)
10447 //=================================================================================================================
10449 
10450 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
10451 
10452 HWND _txConsole_Attach()
10453  {
10454 $1 HWND console = Win32::GetConsoleWindow();
10455 
10456 $ if (!console)
10457  {
10458 $ bool minimizeConsole = ((TX_CONSOLE_MODE) == SW_HIDE && !_txIsConsoleSubsystem());
10459 
10460 $ Win32::TEB* teb = (Win32::TEB*) NtCurrentTeb();
10461 $ assert (teb);
10462 $ assert (teb->ProcessEnvironmentBlock);
10463 
10464 $ Win32::RTL_USER_PROCESS_PARAMETERS* params = teb->ProcessEnvironmentBlock->ProcessParameters;
10465 $ assert (params);
10466 
10467 $ if (minimizeConsole) // The fact that ShowWindow parameter of the program's console is taken from calling
10468  // process' STARTUPINFO, was researched from Windows XP sources. See SetUpConsoleInfo()
10469  // in windows\core\ntcon\client\dllinit.c. No one can miss stealing Windows sources. :(
10470  // Thank you Matt Pietrek, the author of "Undocumented Windows". Use the Source, Luke!..
10471  {
10472 $ params->dwFlags |= STARTF_USESHOWWINDOW;
10473 $ params->wShowWindow = SW_MINIMIZE;
10474  }
10475 
10476 $ AllocConsole();
10477 $ console = Win32::GetConsoleWindow();
10478  }
10479 
10480 $ if (!console) return NULL;
10481 
10482 $ txSetLocale(); // Устанавливаем русскую кодовую страницу для консоли Windows
10483 
10484 $ _txConsole_SetUnicodeFont(); // Впечатлительным лучше сюда не смотреть.
10485 
10486 $ if (!_txIsConsoleSubsystem())
10487  {$ txReopenStdio(); } // Переоткрываем потоки ввода-вывода, если subsystem != console
10488 
10489 $ return console;
10490  }
10491 
10492 //-----------------------------------------------------------------------------------------------------------------
10493 
10494 int txSetLocale (int codepage /*= _TX_CODEPAGE*/,
10495  const char locale[] /*= _TX_LOCALE*/, const wchar_t wLocale[] /*= _TX_WLOCALE*/)
10496  {
10497 $1 int oldPage = GetConsoleOutputCP();
10498 
10499  // Устанавливаем нужную кодовую страницу для консоли Windows
10500 
10501 $ if (codepage)
10502  {
10503 $ SetConsoleCP (codepage);
10504 $ SetConsoleOutputCP (codepage);
10505  }
10506 
10507  // Устанавливаем нужную кодовую страницу для стандартной библиотеки, иначе не будут работать Unicode-версии
10508  // функций (wprintf, ...). Если компилите с помощью gcc и собираетесь использовать L"unicode-строки" с определенным
10509  // языком, укажите опции в командной строке компилятора g++: -finput-charset=NNNN -fexec-charset=NNNN, где NNNN -
10510  // обозначение кодовой страницы (например, для русского языка - CP1251).
10511 
10512 $ if (locale)
10513  {
10514 $ setlocale (LC_ALL, locale);
10515 $ setlocale (LC_NUMERIC, "C"); // Return to decimal point (3.14) instead of comma (3,14) in floating numbers
10516  }
10517 
10518  #ifndef __CYGWIN__
10519 
10520 $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility.
10521 
10522 $ if (wLocale && !wine)
10523  {
10524 $ _wsetlocale (LC_ALL, wLocale);
10525 $ _wsetlocale (LC_NUMERIC, L"C"); // L"C" (see above)
10526  }
10527 
10528  #endif
10529 
10530  (void) wLocale;
10531 
10532 $ return oldPage;
10533  }
10534 
10535 //-----------------------------------------------------------------------------------------------------------------
10536 
10537 void txReopenStdio()
10538  {
10539 $1 // Переоткрываем заново <s>Америку
10540 
10541 $ fflush (stdout);
10542 $ fflush (stderr);
10543 
10544 $ FILE* f = NULL;
10545 
10546  #ifndef __CYGWIN__
10547 
10548 $ f = _fdopen (_open_osfhandle ((intptr_t) GetStdHandle (STD_INPUT_HANDLE), _O_TEXT), "r"); assert (f); *stdin = *f;
10549 $ f = _fdopen (_open_osfhandle ((intptr_t) GetStdHandle (STD_OUTPUT_HANDLE), _O_TEXT), "w"); assert (f); *stdout = *f;
10550 $ f = _fdopen (_open_osfhandle ((intptr_t) GetStdHandle (STD_ERROR_HANDLE), _O_TEXT), "w"); assert (f); *stderr = *f;
10551 
10552  #else
10553 
10554 $ f = _fdopen (STDIN_FILENO, "r"); assert (f); *stdin = *f;
10555 $ f = _fdopen (STDOUT_FILENO, "w"); assert (f); *stdout = *f;
10556 $ f = _fdopen (STDERR_FILENO, "w"); assert (f); *stderr = *f;
10557 
10558  #endif
10559 
10560 $ setvbuf (stdin, NULL, _IONBF, 0);
10561 $ setvbuf (stdout, NULL, _IONBF, 0);
10562 $ setvbuf (stderr, NULL, _IONBF, 0);
10563 
10564 $ ::std::ios::sync_with_stdio();
10565  }
10566 
10567 //-----------------------------------------------------------------------------------------------------------------
10568 
10569 inline bool _txConsole_OK()
10570  {
10571  return Win32::GetConsoleWindow() != NULL;
10572  }
10573 
10574 //-----------------------------------------------------------------------------------------------------------------
10575 
10576 bool _txConsole_Detach (bool activate)
10577  {
10578 $1 HWND console = Win32::GetConsoleWindow();
10579 $ if (!console) return false;
10580 
10581 $ EnableWindow (console, true);
10582 
10583 $ if (activate)
10584  {
10585 $ if (!IsWindowVisible (console))
10586  {$ ShowWindow (console, SW_MINIMIZE); }
10587 
10588 $ _txActivateWindow (console, 0xFF);
10589 $ return true;
10590  }
10591  else
10592  {
10593 $ return !!FreeConsole();
10594  }
10595  }
10596 
10597 //-----------------------------------------------------------------------------------------------------------------
10598 
10599 bool _txConsole_Draw (HDC dc)
10600  {
10601 $8 if (_TX_HDC_FAILED (dc)) return false;
10602 
10603 $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE);
10604 
10605 $ CONSOLE_SCREEN_BUFFER_INFO con = {};
10606 $ BOOL ok = GetConsoleScreenBufferInfo (out, &con);
10607 $ if (!ok) return false;
10608 
10609 $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1,
10610  con.srWindow.Bottom - con.srWindow.Top + 1 };
10611 
10612 $ SIZE fontSz = { 12, 16 };
10613 $ Win32::GetTextExtentPoint32 (dc, "W", 1, &fontSz) asserted;
10614 
10615 $ COLORREF pal [16] = { 0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xC0C0C0,
10616  0x808080, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF };
10617 
10618 $ for (short y = 0; y < size.y; y++)
10619  {
10620  static char chr [_TX_BUFSIZE + 1] = ""; // [con.dwSize.X + 1]; maybe will be truncated
10621  static WORD atr [_TX_BUFSIZE + 1] = {}; // [con.dwSize.X + 1]; maybe will be truncated
10622  COORD coord = { (short) (con.srWindow.Left), (short) (y + con.srWindow.Top) };
10623  DWORD read = 0;
10624 
10625  if (!ReadConsoleOutputCharacter (out, chr, sizearr (chr) - 1, coord, &read)) continue;
10626  if (!ReadConsoleOutputAttribute (out, atr, sizearr (atr) - 1, coord, &read)) continue;
10627 
10628  for (int x = 0, xEnd = size.x; x < size.x; x = xEnd)
10629  {
10630  Win32::SetTextColor (dc, pal [ atr[x] & 0x0F]);
10631  Win32::SetBkColor (dc, pal [(atr[x] >> 4) & 0x0F]);
10632  Win32::SetBkMode (dc, (atr[x] & 0xF0)? OPAQUE : TRANSPARENT);
10633 
10634  for (xEnd = x+1; xEnd < size.x && atr[xEnd] == atr[x]; xEnd++) {;}
10635 
10636  Win32::TextOut (dc, ROUND (fontSz.cx * (x + con.srWindow.Left)),
10637  ROUND (fontSz.cy * y), chr + x, xEnd - x) asserted;
10638  }
10639  }
10640 
10641 $ Win32::SetTextColor (dc, pal [ con.wAttributes & 0x0F]);
10642 $ Win32::SetBkColor (dc, pal [(con.wAttributes >> 4) & 0x0F]);
10643 $ Win32::SetBkMode (dc, TRANSPARENT);
10644 
10645 $ if (_txConsole_IsBlinking &&
10646  In (std::nomeow, con.dwCursorPosition, con.srWindow) &&
10647  GetTickCount() % _txCursorBlinkInterval*2 > _txCursorBlinkInterval &&
10648  GetForegroundWindow() == txWindow())
10649  {
10650 $ Win32::TextOut (dc, ROUND (fontSz.cx * (con.dwCursorPosition.X - con.srWindow.Left)),
10651  ROUND (fontSz.cy * (con.dwCursorPosition.Y - con.srWindow.Top)) + 1,
10652  "_", 1) asserted;
10653  }
10654 
10655 $ return true;
10656  }
10657 
10658 #endif // TX_COMPILED
10659 
10660 //-----------------------------------------------------------------------------------------------------------------
10661 //{ Welcome to the Duck Side! Together we will rule the Bathroom!
10662 //-----------------------------------------------------------------------------------------------------------------
10663 
10664 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
10665 
10666 bool _txConsole_SetUnicodeFont()
10667  {
10668 $ const bool wine = !!Win32::wine_get_version; // Linux::Wine v1.2.2+ compatibility.
10669  // Beer compatibility may be added in future versions...
10670 $ if (wine) // Минздрав РФ предупреждает: чрезмерное употребление wine
10671  { // вредит Вашему здоровью.
10672 $ Win32::GetNumberOfConsoleFonts = NULL;
10673 $ Win32::GetCurrentConsoleFont = NULL;
10674 $ Win32::SetConsoleFont = NULL;
10675 
10676 $ return false;
10677  }
10678 
10679  // Начиная с Висты все хорошо...
10680 
10681 $1 if (Win32::GetCurrentConsoleFontEx && Win32::SetCurrentConsoleFontEx)
10682  {
10683 $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE);
10684 
10685 $ Win32::CONSOLE_FONT_INFOEX info = { sizeof (info) };
10686 $ if (!Win32::GetCurrentConsoleFontEx (out, false, &info)) return false;
10687 
10688 $ info.FontFamily = 0x36; // Unicode fixed-pitch
10689 $ if (!*info.FaceName) info.dwFontSize.Y = (SHORT) (info.dwFontSize.Y + 2); // Terminal font is too small
10690 
10691 $ if (wcsncmp (info.FaceName, L"Consolas", sizearr (info.FaceName)) != 0) // Consolas is allowed too
10692  {$ wcsncpy_s (info.FaceName, sizearr (info.FaceName), L"Lucida Console", sizearr (info.FaceName)); }
10693 
10694 $ return !!Win32::SetCurrentConsoleFontEx (out, false, &info);
10695  }
10696 
10697  // ...а до этого все не так сладко
10698 
10699 $ const unsigned uniFont = 10; // The Internet and W2K sources know this magic number
10700 $ const unsigned uniSize = 20; // Size of the font desired, should be > max # of Raster Fonts //-V2551
10701 $ bool ok = true;
10702 
10703  // Force Windows to use Unicode font by creating and run the console shortcut tuned to use that font.
10704 
10705 $ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE);
10706 
10707 $ unsigned fonts = _TX_CALL (Win32::GetNumberOfConsoleFonts, ());
10708 $ if (fonts && fonts <= uniFont)
10709  {
10710 $ HRESULT init = Win32::CoInitialize (NULL);
10711 $ size_t sz = 0;
10712 
10713 $ char link [MAX_PATH] = "";
10714 $ getenv_s (&sz, link, sizeof (link) - 1, "TEMP");
10715 $ strncat_s (link, sizeof (link), "\\~txLink.lnk", sizeof (link) - 1);
10716 
10717 $ char comspec [MAX_PATH] = "";
10718 $ getenv_s (&sz, comspec, sizeof (comspec), "COMSPEC");
10719 
10720 $ (void) _unlink (link);
10721 
10722 $ _txCreateShortcut (link, comspec, "/c exit", NULL, NULL, SW_SHOWMINNOACTIVE, NULL, 0, uniSize) asserted;
10723 
10724 $ ok = (Win32::ShellExecuteA (NULL, NULL, link, NULL, NULL, SW_SHOWMINNOACTIVE) > (void*)32); // Sic! //-V112 //-V566
10725  if (ok) {$ _txWaitFor (FindWindow (NULL, "~txLink"), _TX_TIMEOUT); }
10726 
10727 $ (void) _unlink (link);
10728 
10729 $ if (init == S_OK) Win32::CoUninitialize();
10730  }
10731 
10732  // If Unicode font is not already set, do set it.
10733 
10734 $ Win32::CONSOLE_FONT_INFO cur = {};
10735 $ _TX_CALL (Win32::GetCurrentConsoleFont, (out, false, &cur));
10736 
10737 $ ok &= (cur.nFont >= uniFont);
10738  if (!ok) {$ ok &= _TX_CALL (Win32::SetConsoleFont, (out, uniFont)); }
10739 
10740 $ HWND console = Win32::GetConsoleWindow();
10741 $ InvalidateRect (console, NULL, false);
10742 $ UpdateWindow (console);
10743 
10744 $ return ok;
10745  }
10746 
10747 #endif // TX_COMPILED
10748 
10749 //-----------------------------------------------------------------------------------------------------------------
10750 //{ The assistants to the nightmare. You can use it freely to make your own nightmare sweet.
10751 
10752 #define _TX_TRY { goto __tx_try; } __tx_try: { int __tx_error = S_OK; (void)__tx_error;
10753 #define _TX_CHECKED( cmd ) { if (FAILED (__tx_error = (cmd))) goto __tx_catch; }
10754 #define _TX_FAIL { __tx_error = E_FAIL; goto __tx_catch; }
10755 #define _TX_RETRY { __tx_error = S_OK; goto __tx_try; }
10756 #define _TX_OK ( SUCCEEDED (__tx_error) )
10757 #define _TX_CATCH goto __tx_finally; __tx_catch:
10758 #define _TX_RETURN goto __tx_finally;
10759 #define _TX_FINALLY __tx_finally:
10760 #define _TX_ENDTRY }
10761 
10762 //}
10763 //-----------------------------------------------------------------------------------------------------------------
10764 
10765 // Мало не покажется
10766 
10767 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
10768 
10769 bool _txCreateShortcut (const char shortcutName[],
10770  const char fileToLink[], const char args[] /*= NULL*/, const char workDir[] /*= NULL*/,
10771  const char description[] /*= NULL*/, int cmdShow /*= SW_SHOWNORMAL*/, const char iconFile[] /*= NULL*/, int iconIndex /*= 0*/,
10772  int fontSize /*= 0*/, COORD bufSize /*= ZERO (COORD)*/, COORD wndSize /*= ZERO (COORD)*/, COORD wndOrg /*=ZERO (COORD)*/)
10773  {
10774 $1 if (_TX_ARGUMENT_FAILED (shortcutName && *shortcutName)) return false;
10775 $ if (_TX_ARGUMENT_FAILED (fileToLink && *fileToLink)) return false;
10776 
10777  #if defined (__IShellLinkDataList_INTERFACE_DEFINED__)
10778 
10779 $ IShellLink* shellLink = NULL;
10780 $ IShellLinkDataList* dataList = NULL;
10781 $ IPersistFile* file = NULL;
10782 
10783 $ HRESULT init = Win32::CoInitialize (NULL);
10784 
10785  _TX_TRY
10786  {
10787 $ _TX_CHECKED (Win32::CoCreateInstance (CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, Win32::IID_IShellLink, (void**) &shellLink));
10788 $ if (!shellLink) _TX_FAIL;
10789 
10790 $ shellLink->SetPath (fileToLink);
10791 $ shellLink->SetArguments (args);
10792 $ shellLink->SetWorkingDirectory (workDir);
10793 $ shellLink->SetDescription (description);
10794 $ shellLink->SetShowCmd (cmdShow);
10795 $ shellLink->SetIconLocation (iconFile, iconIndex);
10796 
10797 $ _TX_CHECKED (shellLink->QueryInterface (Win32::IID_IShellLinkDataList, (void**) &dataList));
10798 $ if (!dataList) _TX_FAIL;
10799 
10800 $ Win32::NT_CONSOLE_PROPS props =
10801  {{sizeof (props), NT_CONSOLE_PROPS_SIG},
10802 
10803  FOREGROUND_LIGHTGRAY, // wFillAttribute
10804  FOREGROUND_MAGENTA | BACKGROUND_WHITE, // wPopupFillAttribute
10805  {bufSize.X, bufSize.Y}, // dwScreenBufferSize
10806  {wndSize.X, wndSize.Y}, // dwWindowSize
10807  {wndOrg.X, wndOrg.Y}, // dwWindowOrigin
10808  0, // nFont
10809  0, // nInputBufferSize
10810  {0, (short) fontSize}, // dwFontSize
10811  0x36, 400, L"Lucida Console", // uFontFamily, uFontWeight, FaceName. We're dancing for this!
10812  15, // uCursorSize
10813  0, 1, 1, 0, // bFullScreen, bQuickEdit, bInsertMode, bAutoPosition
10814  50, 4, 0, // uHistoryBufferSize, uNumberOfHistoryBuffers, bHistoryNoDup
10815 
10816  {0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xC0C0C0, // Palette
10817  0x808080, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF}
10818  };
10819 
10820 $ _TX_CHECKED (dataList->AddDataBlock (&props));
10821 
10822 $ _TX_CHECKED (shellLink->QueryInterface (Win32::IID_IPersistFile, (void**) &file));
10823 $ if (!file) _TX_FAIL;
10824 
10825 $ wchar_t wName[MAX_PATH] = L"";
10826 $ MultiByteToWideChar (_TX_CODEPAGE, 0, shortcutName, -1, wName, MAX_PATH) || ZeroMemory (wName, sizeof (wName));
10827 
10828 $ _TX_CHECKED (file->Save (wName, true));
10829  }
10830 
10831 $ _TX_CATCH
10832 $ _TX_FINALLY
10833 
10834  if (file) {$ file ->Release(); }
10835  if (dataList) {$ dataList ->Release(); }
10836  if (shellLink) {$ shellLink->Release(); }
10837 
10838  if (init == S_OK) {$ Win32::CoUninitialize(); }
10839 
10840 $ return _TX_OK;
10841  _TX_ENDTRY
10842 
10843  #else
10844 
10845  (void) args; (void) workDir, (void) description; (void) cmdShow; (void) iconFile; (void) iconIndex;
10846  (void) fontSize; (void) bufSize; (void) wndSize; (void) wndOrg;
10847 
10848 $ return false;
10849 
10850  #endif
10851  }
10852 
10853 #endif // TX_COMPILED
10854 
10855 //}
10856 //-----------------------------------------------------------------------------------------------------------------
10857 
10859 //}
10860 //=================================================================================================================
10861 
10862 //=================================================================================================================
10863 //{ Memory DC functions (_txBuffer...)
10865 //=================================================================================================================
10867 
10868 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
10869 
10870 HDC _txBuffer_Create (HWND wnd, const POINT* size /*= NULL*/, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/)
10871  {
10872 $1 txAutoLock _lock;
10873 
10874 $ HDC wndDC = GetDC (wnd);
10875 $ if (!wndDC) return NULL;
10876 
10877 $ POINT sz = { 1, 1 };
10878 $ if (size) sz = *size;
10879 
10880 $ if (!size && wnd)
10881  {
10882 $ RECT r = {};
10883 $ GetClientRect (wnd, &r) asserted;
10884 
10885 $ sz.x = r.right - r.left;
10886 $ sz.y = r.bottom - r.top;
10887  }
10888 
10889 $ if (bitmap)
10890  {
10891 $ BITMAP bmap = {};
10892 $ Win32::GetObject (bitmap, sizeof (bmap), &bmap) asserted;
10893 
10894 $ sz.x = bmap.bmWidth;
10895 $ sz.y = bmap.bmHeight;
10896  }
10897 
10898 $ RGBQUAD* buf = NULL;
10899 $ if (!pixels) pixels = &buf;
10900 
10901 $ HDC dc = Win32::CreateCompatibleDC (wndDC);
10902 $ if (!dc) TX_DEBUG_ERROR ("Cannot create buffer: CreateCompatibleDC() failed");
10903 
10904  #ifndef _TX_DIB_FIX
10905  #define _TX_DIB_FIX
10906  #endif
10907 
10908 $ BITMAPINFO info = {{ sizeof (info), sz.x, _TX_DIB_FIX sz.y, 1, WORD (sizeof (RGBQUAD) * 8), BI_RGB }};
10909 
10910 $ HBITMAP bmap = bitmap? bitmap : Win32::CreateDIBSection (NULL, &info, DIB_RGB_COLORS, (void**) pixels, NULL, 0);
10911 $ if (!bmap) TX_DEBUG_ERROR ("Cannot create buffer: CreateCompatibleBitmap() failed");
10912 
10913 $ Win32::SelectObject (dc, bmap) asserted;
10914 
10915 $ if (!bitmap)
10916  {
10917 $ if (*pixels)
10918  {
10919 $ RGBQUAD black = { 0, 0, 0, 255 };
10920 $ for (int i = 0; i < sz.x * sz.y; i++) (*pixels)[i] = black; //-V108
10921  }
10922  else
10923  {$ Win32::PatBlt (dc, 0, 0, sz.x, sz.y, BLACKNESS) asserted; }
10924  }
10925 
10926 $ ReleaseDC (wnd, wndDC) asserted;
10927 
10928 $ return dc;
10929  }
10930 
10931 //-----------------------------------------------------------------------------------------------------------------
10932 
10933 bool _txBuffer_Delete (HDC* dc)
10934  {
10935 $1 if (_TX_ARGUMENT_FAILED (dc)) return false;
10936 $ if ( !*dc) return false;
10937 $ if (_TX_HDC_FAILED (*dc)) return false;
10938 
10939 $ if (!Win32::GetObjectType (Win32::GetCurrentObject (*dc, OBJ_BITMAP))) return false;
10940 
10941 $ txAutoLock _lock;
10942 
10943 $ _txBuffer_Select (Win32::GetStockObject (NULL_PEN), *dc) asserted;
10944 $ _txBuffer_Select (Win32::GetStockObject (NULL_BRUSH), *dc) asserted;
10945 $ _txBuffer_Select (Win32::GetStockObject (SYSTEM_FONT), *dc) asserted;
10946 $ _txBuffer_Select (_txStockBitmap, *dc);
10947 
10948 $ Win32::DeleteObject (Win32::GetCurrentObject (*dc, OBJ_BITMAP)) asserted;
10949 
10950 $ Win32::DeleteDC (*dc) asserted;
10951 
10952 $ *dc = NULL;
10953 
10954 $ return true;
10955  }
10956 
10957 //-----------------------------------------------------------------------------------------------------------------
10958 
10959 bool _txBuffer_Select (HGDIOBJ obj, HDC dc /*= txDC()*/)
10960  {
10961 $1 if (!obj) return false;
10962 $ if (_TX_HDC_FAILED (dc)) return false;
10963 
10964 $ if (!Win32::GetObjectType (obj)) TX_DEBUG_ERROR ("Invalid GDI object type");
10965 
10966 $ txAutoLock _lock;
10967 
10968 $ obj = Win32::SelectObject (dc, obj);
10969 $ if (obj) Win32::DeleteObject (obj);
10970 
10971 $ return obj != NULL;
10972  }
10973 
10974 #endif // TX_COMPILED
10975 
10977 //}
10978 //=================================================================================================================
10979 
10980 //=================================================================================================================
10981 //{ Diagnostics
10983 //=================================================================================================================
10985 
10986 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
10987 
10988 const char* _txError (const char* file /*= NULL*/, int line /*= 0*/, const char* func /*= NULL*/, unsigned color /*= 0*/,
10989  const char* msg /*= NULL*/, ...)
10990  { //---/\---/\-------Это ASCII KOT!--//
10991 $1 va_list arg; va_start (arg, msg); // { '-' } //
10992 $$ const char* what = _txProcessError (file, line, func, color, msg, arg); // { 0 0 } Добавь его себе //
10993  va_end (arg); // --> V <-- в исходник, и тебе //
10994  // \ \|/ / будет, наверно, //
10995  if (!(msg && msg[0] == '\a')) return what; // \___/ приятно отлаживаться //
10996  //---------------долгими ночами:)--//
10997 // vvvvvvvvvvvvvvvvvv
10998  DebugBreak(); // >>> Котики, вы в отладчике. Не пугайтесь. Есть шанс посмотреть переменные и разобраться.
10999 // ^^^^^^^^^^^^^^^^^^
11000 
11001  return what; // >>> Уходите из функции пошаговой отладкой (F10/F11). Следите за стеком вызовов (Alt+7).
11002  }
11003 
11004 #endif // TX_COMPILED
11005 
11006 //-----------------------------------------------------------------------------------------------------------------
11007 //{ General runtime check hooks
11008 //-----------------------------------------------------------------------------------------------------------------
11009 
11010 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
11011 
11012 void _txOnSignal (int sig /*= 0*/, int fpe /*= 0*/)
11013  {
11014 $1 if (!sig && !fpe)
11015  {
11016 $ signal (SIGSEGV, (void(*)(int))(uintptr_t)_txOnSignal) != SIG_ERR asserted;
11017 $ signal (SIGFPE, (void(*)(int))(uintptr_t)_txOnSignal) != SIG_ERR asserted;
11018 $ signal (SIGABRT, (void(*)(int))(uintptr_t)_txOnSignal) != SIG_ERR asserted;
11019 $ signal (SIGILL, (void(*)(int))(uintptr_t)_txOnSignal) != SIG_ERR asserted;
11020 $ signal (SIGTERM, (void(*)(int))(uintptr_t)_txOnSignal) != SIG_ERR asserted;
11021 $ return;
11022  }
11023 
11024  txOutputDebugPrintf ("%s - WARNING: %s (%d, %d) called\n", _TX_VERSION, __func__, sig, fpe);
11025 
11026  #define GET_DESCR_(str, code, descr) case (code): {$ (str) = " " #code ": " descr; break; }
11027 
11028 $ const char* sSig = "Неизвестный тип сигнала; $ switch (sig) { GET_DESCR_ (sSig, SIGSEGV, "Доступ по неверному указателю. Ставьте ассерты!") GET_DESCR_ (sSig, SIGILL, "Попытка выполнить недопустимую операцию. Проверьте указатели на функции.") GET_DESCR_ (sSig, SIGABRT, "Аварийное завершение программы, вызвана функция abort().") GET_DESCR_ (sSig, SIGTERM, "Получен сигнал принудительного завершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call";
11029 
11030 $ switch (sig)
11031  {
11032  GET_DESCR_ (sSig, SIGSEGV, "Доступ по неверному указателю. Ставьте ассерты!")
11033  GET_DESCR_ (sSig, SIGILL, "Попыткавыполнить недопустимую операцию. Проверьте указатели на функции.") GET_DESCR_ (sSig, SIGABRT, "Аварийное завершение программы, вызвана функция abort().") GET_DESCR_ (sSig, SIGTERM, "Получен сигнал принудительного завершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call выполнитьнедопустимую операцию. Проверьте указатели на функции.") GET_DESCR_ (sSig, SIGABRT, "Аварийное завершение программы, вызвана функция abort().") GET_DESCR_ (sSig, SIGTERM, "Получен сигнал принудительного завершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call недопустимую операцию. Проверьтеуказатели на функции.") GET_DESCR_ (sSig, SIGABRT, "Аварийное завершение программы, вызвана функция abort().") GET_DESCR_ (sSig, SIGTERM, "Получен сигнал принудительного завершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call указателина функции.") GET_DESCR_ (sSig, SIGABRT, "Аварийное завершение программы, вызвана функция abort().") GET_DESCR_ (sSig, SIGTERM, "Получен сигнал принудительного завершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call на функции") GET_DESCR_ (sSig, SIGABRT, "Аварийное завершение программы, вызвана функция abort().") GET_DESCR_ (sSig, SIGTERM, "Получен сигнал принудительного завершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call.")
11034  GET_DESCR_ (sSig, SIGABRT, "Аварийноезавершение программы, вызвана функция abort().") GET_DESCR_ (sSig, SIGTERM, "Получен сигнал принудительного завершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call завершение программы вызвана функция abort().") GET_DESCR_ (sSig, SIGTERM, "Получен сигнал принудительного завершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call, вызванафункция abort().") GET_DESCR_ (sSig, SIGTERM, "Получен сигнал принудительного завершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call функция abort().")
11035  GET_DESCR_ (sSig, SIGTERM, "Полученсигнал принудительного завершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call сигнал принудительногозавершения программы.") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call завершения программы") GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка в вычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call.")
11036  GET_DESCR_ (sSig, SIGFPE, "Грубая ошибка ввычислениях.") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call вычислениях") default: break; //-V2522 } $ const char* sFPE = ""; #if defined (_MSC_VER) // MSVC provides the FPE code as a MS extension. // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx $ if (sig == SIGFPE) switch (fpe) { GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.") GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.") GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Деление на ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call.")
11037  default: break; //-V2522
11038  }
11039 
11040 $ const char* sFPE = "";
11041 
11042  #if defined (_MSC_VER)
11043 
11044  // MSVC provides the FPE code as a MS extension.
11045  // See: https://msdn.microsoft.com/ru-ru/library/xdkz3x12.aspx
11046 
11047 $ if (sig == SIGFPE) switch (fpe)
11048  {
11049  GET_DESCR_ (sFPE, _FPE_INVALID, "Результат неверен.")
11050  GET_DESCR_ (sFPE, _FPE_DENORMAL, "Денормализация.")
11051  GET_DESCR_ (sFPE, _FPE_ZERODIVIDE, "Делениена ноль.") GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результат слишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call на ноль.")
11052  GET_DESCR_ (sFPE, _FPE_OVERFLOW, "Результатслишком большой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call слишкомбольшой.") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call большой") GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результат слишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call.")
11053  GET_DESCR_ (sFPE, _FPE_UNDERFLOW, "Результатслишком маленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call слишкоммаленький.") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call маленький") GET_DESCR_ (sFPE, _FPE_INEXACT, "Результат неточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call.")
11054  GET_DESCR_ (sFPE, _FPE_INEXACT, "Результатнеточен.") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call неточен") GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.") GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа.") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call.")
11055  GET_DESCR_ (sFPE, _FPE_UNEMULATED, "Операция не поддерживается.")
11056  GET_DESCR_ (sFPE, _FPE_SQRTNEG, "Квадратный корень из отрицательного числа") GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стека сопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call.")
11057  GET_DESCR_ (sFPE, _FPE_STACKOVERFLOW, "Переполнение стекасопроцессора.") GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "В стеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call сопроцессора.")
11058  GET_DESCR_ (sFPE, _FPE_STACKUNDERFLOW, "Встеке сопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call стекесопроцессора не хватает данных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call сопроцессора не хватаетданных.") GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явный вызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call данных.")
11059  GET_DESCR_ (sFPE, _FPE_EXPLICITGEN, "Явныйвызов исключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call вызовисключения.") default: break; //-V2522 } #else $ fpe = 0; #endif #undef GET_DESCR_ $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal); $ Win32::_fpreset(); $ _TX_UNEXPECTED ("\a\t" "signal (%d, 0x%02X):%s%s " "%s%s" "С помощью функции signal() вы можете сами обработать эту ошибку.", sig, (unsigned) fpe, sSig, sFPE, ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnTerminate() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc $1 static int terminating = 0; if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; } $ if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("\t\a" "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, " "или другая фатальная ошибка C++. " "%s" "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, " "разбирайтесь, в чем дело.\n\n" "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE, _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- void _txOnUnexpected() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 if (!*_txDumpSE) {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); } $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n" "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете " "спецификацию исключений для функций, проверьте, не нарушена ли она." "%s" "С помощью catch (...) в main() вы можете сами обработать эту ошибку.", _txDumpSE + 1); } //----------------------------------------------------------------------------------------------------------------- int _txOnMatherr (_exception* exc) { txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc); $1 assert (exc); const char* sType = "Неизвестный тип исключения"; #if !defined (__CYGWIN__) #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; } $ switch (exc->type) { GET_DESCR_ (_DOMAIN, "Нарушение области определения"); GET_DESCR_ (_SING, "Сингулярность аргумента"); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call исключения.")
11060  default: break; //-V2522
11061  }
11062 
11063  #else
11064 $ fpe = 0;
11065  #endif
11066 
11067  #undef GET_DESCR_
11068 
11069 $ signal (sig, (void(*)(int))(uintptr_t)_txOnSignal);
11070 
11071 $ Win32::_fpreset();
11072 
11073 $ _TX_UNEXPECTED ("\a\t"
11074  "signal (%d, 0x%02X):%s%s "
11075  "%s%s"
11076  "С помощью функции signal() вы можете сами обработать эту ошибку.",
11077  sig, (unsigned) fpe, sSig, sFPE,
11078  ((_txDumpSE[1] == '\n')? "" : "\n\n"), _txDumpSE + 1);
11079  }
11080 
11081 //-----------------------------------------------------------------------------------------------------------------
11082 
11083 void _txOnTerminate()
11084  {
11085  txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__);
11086 
11087  // From: http://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/vterminate.cc
11088 
11089 $1 static int terminating = 0;
11090  if (terminating++) {$ _TX_UNEXPECTED ("\a" "std::terminate() вызвана рекурсивно."); return; }
11091 
11092 $ if (!*_txDumpSE)
11093  {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); }
11094 
11095 $ _TX_UNEXPECTED ("\t\a"
11096  "std::terminate(): Неперехваченное исключение в функции main() или в деструкторе, "
11097  "или другая фатальная ошибка C++. "
11098  "%s"
11099  "Используйте try/catch блоки, перехватывайте catch (...), проверяйте вызовы виртуальных функций, "
11100  "разбирайтесь, в чем дело.\n\n"
11101  "С помощью std::set_terminate() вы можете сами обработать эту ошибку." + !*_txDumpSE,
11102  _txDumpSE + 1);
11103  }
11104 
11105 //-----------------------------------------------------------------------------------------------------------------
11106 
11107 void _txOnUnexpected()
11108  {
11109  txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__);
11110 
11111 $1 if (!*_txDumpSE)
11112  {$ _txDumpExceptionCPP (_txDumpSE + 1, sizeof (_txDumpSE) - 2); }
11113 
11114 $ _TX_UNEXPECTED ("std::unexpected(): Необработанное исключение.\n\n"
11115  "Проверьте свои catch-блоки. Перехватите catch (...). Если вы (зря) используете "
11116  "спецификацию исключений для функций, проверьте, не нарушена ли она."
11117  "%s"
11118  "С помощью catch (...) в main() вы можете сами обработать эту ошибку.",
11119  _txDumpSE + 1);
11120  }
11121 
11122 //-----------------------------------------------------------------------------------------------------------------
11123 
11124 int _txOnMatherr (_exception* exc)
11125  {
11126  txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*) exc);
11127 
11128 $1 assert (exc);
11129 
11130  const char* sType = "Неизвестный тип исключения";
11131 
11132  #if !defined (__CYGWIN__)
11133 
11134  #define GET_DESCR_(code, descr) case (code): {$ sType = "(" #code "): " descr; break; }
11135 
11136 $ switch (exc->type)
11137  {
11138  GET_DESCR_ (_DOMAIN, "Нарушение области определения");
11139  GET_DESCR_ (_SING, "Сингулярность аргумента); GET_DESCR_ (_PLOSS, "Частичная потеря значимости"); GET_DESCR_ (_TLOSS, "Полная потеря значимости"); GET_DESCR_ (_OVERFLOW, "Результат слишком большой"); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call");
11140  GET_DESCR_ (_PLOSS, "Частичная потеря значимости");
11141  GET_DESCR_ (_TLOSS, "Полная потеря значимости");
11142  GET_DESCR_ (_OVERFLOW, "Результат слишком большой); GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький"); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call");
11143  GET_DESCR_ (_UNDERFLOW, "Результат слишком маленький); default: break; //-V2522 } #undef GET_DESCR_ $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n" "С помощью __setusermatherr() вы можете сами обработать эту ошибку.", exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval); #else $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType); #endif return 0; } //----------------------------------------------------------------------------------------------------------------- tx_noreturn void _txOnNewHandlerAnsi() { txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__); $1 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n" "С помощью std::set_new_handler() вы можете сами обработать эту ошибку " "и где-нибудь найти недостающую память."); $ throw std::bad_alloc(); } //----------------------------------------------------------------------------------------------------------------- void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code) { txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) call");
11144  default: break; //-V2522
11145  }
11146 
11147  #undef GET_DESCR_
11148 
11149 $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка %d %s в функции %s (%g, [%g]). Она вернет значение %g.\n\n"
11150  "С помощью __setusermatherr() вы можете сами обработать эту ошибку.",
11151  exc->type, sType, exc->name, exc->arg1, exc->arg2, exc->retval);
11152  #else
11153 
11154 $ _TX_UNEXPECTED ("_matherr(): Математическая ошибка: %s.", sType);
11155 
11156  #endif
11157 
11158  return 0;
11159  }
11160 
11161 //-----------------------------------------------------------------------------------------------------------------
11162 
11163 tx_noreturn void _txOnNewHandlerAnsi()
11164  {
11165  txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__);
11166 $1
11167 $ _TX_UNEXPECTED ("operator new: Ошибка выделения памяти.\n\n"
11168  "С помощью std::set_new_handler() вы можете сами обработать эту ошибку "
11169  "и где-нибудь найти недостающую память.");
11170 
11171 $ throw std::bad_alloc();
11172  }
11173 
11174 //-----------------------------------------------------------------------------------------------------------------
11175 
11176 void _txOnSecurityErrorAnsi (const char* msg, void* ptr, int code)
11177  {
11178  txOutputDebugPrintf ("%s - WARNING: %s (%s, 0x%p, %d) called\n", _TX_VERSION, __func__, msg, ptr, code);
11179 
11180 $1 if (code)
11181  {$ errno = code; }
11182 
11183 $ _TX_UNEXPECTED ("\a"
11184  "Ошибка переполнения буфера %d: %s в %.20s (0x%p). Ставьте ассерты!\n\n"
11185  "С помощью std::set_constraint_handler_s() вы можете сами обработать эту ошибку "
11186  "и постараться не выходить за границы массивов.",
11187  code, msg, (char*) ptr, ptr);
11188  }
11189 
11190 //-----------------------------------------------------------------------------------------------------------------
11191 
11192 int tx_glGetError (int setError /*= INT_MIN*/)
11193  {
11194 $1 _txOGLError = (setError == INT_MIN)? _TX_CALL (Win32::glGetError, ()) : setError;
11195 $ return _txOGLError;
11196  }
11197 
11198 #endif // TX_COMPILED
11199 
11200 //}
11201 //-----------------------------------------------------------------------------------------------------------------
11202 
11203 //-----------------------------------------------------------------------------------------------------------------
11204 //{ MSC Runtime check hooks
11205 //-----------------------------------------------------------------------------------------------------------------
11206 
11207 #if defined (_MSC_VER)
11208 
11209 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
11210 
11211 //-----------------------------------------------------------------------------------------------------------------
11212 
11213 int _txOnNewHandler (size_t size)
11214  {
11215  txOutputDebugPrintf ("%s - WARNING: %s (0x%p) called\n", _TX_VERSION, __func__, (void*)(uintptr_t) size);
11216 $5
11217 $ _TX_UNEXPECTED ("operator new: Ошибка выделения %llu байт памяти.\n\n"
11218  "С помощью _set_new_handler() вы можете сами обработать эту ошибку "
11219  "и где-нибудь найти недостающую память.", (unsigned long long) size);
11220 
11221 $ throw std::bad_alloc();
11222  }
11223 
11224 //-----------------------------------------------------------------------------------------------------------------
11225 
11226 void _txOnSecurityError (int code, void* addr)
11227  {
11228  txOutputDebugPrintf ("%s - WARNING: %s (%d, 0x%p) called\n", _TX_VERSION, __func__, code, addr);
11229 $5
11230 $ _TX_UNEXPECTED ("\a"
11231  "Ошибка переполнения буфера %d (_SECERR_BUFFER_OVERRUN). Ставьте ассерты!\n\n"
11232  "С помощью _set_security_error_handler() вы можете сами обработать эту ошибку "
11233  "и более торжественно завершить программу. Ставьте же ассерты.", code);
11234  }
11235 
11236 //-----------------------------------------------------------------------------------------------------------------
11237 
11238 void _txOnPureCall()
11239  {
11240  txOutputDebugPrintf ("%s - WARNING: %s() called\n", _TX_VERSION, __func__);
11241 $5
11242 $ _TX_UNEXPECTED ("\a"
11243  "Вызвана чисто виртуальная функция. Такое бывает, например, в конструкторах "
11244  "или деструкторах базовых классов - не вызывайте там таких функций.\n\n"
11245  "С помощью _set_purecall_handler() вы можете сами обработать эту ошибку "
11246  "и проверить свое знание С++ :)");
11247  }
11248 
11249 //-----------------------------------------------------------------------------------------------------------------
11250 
11251 void _txOnInvalidParam (const wchar_t* wExpr, const wchar_t* wFunc, const wchar_t* wFile, unsigned int line, uintptr_t addr)
11252  {
11253  txOutputDebugPrintf ("%s - WARNING: %s (%S, %S, %S, %d, 0x%p) called\n", _TX_VERSION, __func__, wExpr, wFunc, wFile, line, addr);
11254 
11255 $5 assert (wExpr);
11256  assert (wFunc);
11257  assert (wFile);
11258 
11259  char expr [_TX_BUFSIZE/2] = "[Unknowm expr]",
11260  func [_TX_BUFSIZE/2] = "[Unknowm func]",
11261  file [MAX_PATH] = "[Unknowm file]";
11262 
11263 $ WideCharToMultiByte (_TX_CODEPAGE, 0, wExpr, -1, expr, sizeof (expr) - 1, NULL, NULL);
11264 $ WideCharToMultiByte (_TX_CODEPAGE, 0, wFunc, -1, func, sizeof (func) - 1, NULL, NULL);
11265 $ WideCharToMultiByte (_TX_CODEPAGE, 0, wFile, -1, file, sizeof (file) - 1, NULL, NULL);
11266 
11267 $$ _txError (file, (int) line, func, 0, "\a"
11268  "В функцию %s передан неверный параметр: неверно, что %s. Не надо так.\n\n"
11269  "С помощью _set_invalid_parameter_handler() вы можете сами обработать эту ошибку.", func, expr);
11270  }
11271 
11272 //-----------------------------------------------------------------------------------------------------------------
11273 
11274 #if defined (_CLANG_VER) && !defined (_MSC_VER)
11275 
11276 void _txLibCppDebugFunction (std::__libcpp_debug_info const& info)
11277  {
11278 $5 assert (&info);
11279 
11280 $$ _txError (info.__file_, info.__line_, NULL, 0, "\a"
11281  "Оказалось неверно, что %s (%s). Не надо так.\n\n"
11282  "С помощью std::__libcpp_debug_function вы можете сами обработать эту ошибку.", info.__pred_, info.__msg_);
11283  }
11284 
11285 #endif
11286 
11287 //-----------------------------------------------------------------------------------------------------------------
11288 
11289 #pragma runtime_checks ("", off)
11290 
11291 int _txOnRTCFailure (int type, const char* file, int line, const char* module, const char* format, ...)
11292  {
11293  txOutputDebugPrintf ("%s - WARNING: %s (%d, %s, %d, %s, %s) called\n", _TX_VERSION, __func__, type, file, line, module, format);
11294 
11295 $5 static long running = 0;
11296 $ while (InterlockedExchange (&running, 1)) Sleep (0);
11297 
11298 $ assert (format);
11299 
11300  // Disable all RTC failures
11301 
11302 $ int nErrors = _RTC_NumErrors();
11303 $ int* errors = NULL;
11304 $ try { errors = (int*) _alloca (nErrors * sizeof (*errors)); } catch (...) {;} //-V104
11305 
11306 $ int err = 0;
11307 $ for (int i = 0; i < nErrors; i++) *(errors? &errors[i] : &err) = _RTC_SetErrorType ((_RTC_ErrorNumber) i, _RTC_ERRTYPE_IGNORE); //-V108
11308 
11309 $ char text [_TX_BUFSIZE] = "";
11310 
11311 $ va_list arg; va_start (arg, format);
11312 $ _tx_vsnprintf_s (text, sizeof (text) - 1, format, arg); // Get message from the vararg list
11313 $ auto error = (_RTC_ErrorNumber) va_arg (arg, int /*_RTC_ErrorNumber*/); // Get the RTC error number
11314 $ va_end (arg);
11315 
11316 $ const char* sType = "type";
11317 
11318 $ switch (type)
11319  {
11320  case _CRT_ERROR: $ sType = "ошибка"; break;
11321  case _CRT_ASSERT: $ sType = "логическая ошибка"; break;
11322  case _CRT_WARN: $ sType = "возможная ошибка"; break;
11323  default: $ break;
11324  }
11325 
11326 $ const char* sError = _RTC_GetErrDesc (error);
11327 
11328 $$ _txError (file, line, NULL, 0, "\a"
11329  "Сбой проверки выполнения машинного кода: %s %d (%s): %s в модуле %s.", sType, error, sError, text, module);
11330 
11331  // The code below will be never executed until the error above will stay fatal:
11332 
11333  // Restore the RTC error types
11334 
11335  #if defined (_MSC_VER)
11336  #pragma warning (push)
11337  #pragma warning (disable: 6385) // Reading invalid data from 'errors': the readable size is 'n' bytes, but 'm' bytes may be read.
11338  #endif
11339 
11340 $ for (int i = 0; i < nErrors; i++) _RTC_SetErrorType ((_RTC_ErrorNumber) i, (errors? errors[i] : _CRT_ERROR)); //-V108
11341 
11342  #if defined (_MSC_VER)
11343  #pragma warning (pop) // Reading invalid data from 'errors': the readable size is 'n' bytes, but 'm' bytes may be read.
11344  #endif
11345 
11346 $ InterlockedExchange (&running, 0);
11347 $ return 1;
11348  }
11349 
11350 #pragma runtime_checks ("", restore)
11351 
11352 //-----------------------------------------------------------------------------------------------------------------
11353 
11354 int _txOnAllocHook (int type, void* data, size_t size, int use, long request, const unsigned char* file, int line)
11355  {
11356  #if (_TX_ALLOW_TRACE +0 >= 4)
11357 
11358  static _tx_thread int recursive = 0;
11359  if (recursive) return true;
11360  recursive++;
11361 
11362  #if (_TX_ALLOW_TRACE +0 <= 10)
11363  if (!size) return true;
11364  #endif
11365 
11366  #define GET_DESCR_(str, type) case (type): { str = #type; break; }
11367 
11368  const char* sType = "Unknown type";
11369  const char* sUse = "Unknown use";
11370 
11371  switch (_BLOCK_TYPE (type))
11372  {
11373  GET_DESCR_ (sType, _HOOK_ALLOC);
11374  GET_DESCR_ (sType, _HOOK_REALLOC);
11375  GET_DESCR_ (sType, _HOOK_FREE);
11376  default: break;
11377  }
11378 
11379  switch (use)
11380  {
11381  GET_DESCR_ (sUse, _NORMAL_BLOCK);
11382  GET_DESCR_ (sUse, _CRT_BLOCK);
11383  GET_DESCR_ (sUse, _CLIENT_BLOCK);
11384  GET_DESCR_ (sUse, _FREE_BLOCK);
11385  GET_DESCR_ (sUse, _IGNORE_BLOCK);
11386  default: break;
11387  }
11388 
11389  #undef GET_DESCR_
11390 
11391  _txTrace ((const char*) file, line, NULL, "%*s"
11392  "_txOnAllocHook (type = 0x%02X (%-*s), subtype =0x%X, data = 0x%p, size = 0x%p, use = 0x%02X (%-*s), request = %ld)",
11393  2 * _txLoc::Cur.inTX, "",
11394  type, 13, sType, _BLOCK_SUBTYPE (type), data, (void*) size, use, 13, sUse, request);
11395 
11396  recursive--;
11397 
11398  #else
11399 
11400  UNREFERENCED_PARAMETER (type);
11401  UNREFERENCED_PARAMETER (data);
11402  UNREFERENCED_PARAMETER (size);
11403  UNREFERENCED_PARAMETER (use);
11404  UNREFERENCED_PARAMETER (request);
11405  UNREFERENCED_PARAMETER (file);
11406  UNREFERENCED_PARAMETER (line);
11407 
11408  #endif
11409 
11410  return true; //-V601
11411  }
11412 
11413 //-----------------------------------------------------------------------------------------------------------------
11414 
11415 #endif // TX_COMPILED
11416 
11417 #endif
11418 
11419 //}
11420 //-----------------------------------------------------------------------------------------------------------------
11421 
11422 //-----------------------------------------------------------------------------------------------------------------
11423 //{ SEH staff
11424 //-----------------------------------------------------------------------------------------------------------------
11425 
11426 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
11427 
11428 long WINAPI _txVectoredExceptionHandler (EXCEPTION_POINTERS* exc)
11429  {
11431  {
11432  DWORD code = (exc && exc->ExceptionRecord)? exc->ExceptionRecord->ExceptionCode : 0; //-V560
11433  void* addr = (exc && exc->ExceptionRecord)? exc->ExceptionRecord->ExceptionAddress : NULL; //-V560
11434 
11435  if (code != DBG_PRINTEXCEPTION_C &&
11436  code != DBG_PRINTEXCEPTION_WIDE_C)
11437  {
11438  txOutputDebugPrintf ("%s - WARNING: %s (code 0x%08lX, addr 0x%p) called and SKIPPED! (_txProcessSystemWarnings == %d)\n",
11439  _TX_VERSION, "_txVectoredExceptionHandler", (unsigned long) code, addr, _txProcessSystemWarnings);
11440  }
11441 
11442  return EXCEPTION_CONTINUE_SEARCH;
11443  }
11444  else
11445  {
11446  int inTX = _txLoc::Cur.inTX++;
11447 
11448  long ret = _txOnExceptionSEH (exc, "_txVectoredExceptionHandler");
11449 
11450  _txLoc::Cur.inTX = inTX;
11451  return ret;
11452  }
11453  }
11454 
11455 //-----------------------------------------------------------------------------------------------------------------
11456 
11457 long WINAPI _txUnhandledExceptionFilter (EXCEPTION_POINTERS* exc)
11458  {
11459  int inTX = _txLoc::Cur.inTX++;
11460 
11461  long ret = _txOnExceptionSEH (exc, "_txUnhandledExceptionFilter");
11462 
11463  if (_txPrevUEFilter)
11464  {
11465  if (_txSetJmp())
11466  {
11467  int inTX2 = _txLoc::Cur.inTX++;
11468 
11469  ret = _txPrevUEFilter (exc);
11470 
11471  _txLoc::Cur.inTX = inTX2;
11472  }
11473  else
11474  {
11475 $6 _txClearJmp();
11476 
11477  _TX_UNEXPECTED ("\t\a" "%s"
11478  "С помощью функции _set_se_translator() вы можете сами обработать эту ошибку.\n\n"
11479  "Дополнительно: Сбой вызова стандартного обработчика неперехваченнных исключений SEH." + !*_txDumpSE,
11480  _txDumpSE + 1);
11481  }
11482  }
11483 
11484  _txLoc::Cur.inTX = inTX;
11485  return ret;
11486  }
11487 
11488 //-----------------------------------------------------------------------------------------------------------------
11489 
11490 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI _txOnSetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER filter)
11491  {
11492 $6 _txPrevUEFilter = filter;
11493 
11494  return (LPTOP_LEVEL_EXCEPTION_FILTER) _txUnhandledExceptionFilter;
11495  }
11496 
11497 //-----------------------------------------------------------------------------------------------------------------
11498 
11499 long _txOnExceptionSEH (EXCEPTION_POINTERS* exc, const char func[])
11500  {
11501  assert (exc); if (!exc) {$ return EXCEPTION_CONTINUE_SEARCH; } //-V547
11502 
11503  assert (exc->ExceptionRecord);
11504 
11505  assert (func);
11506  assert (func[3] == 'V' || func[3] == 'U');
11507 
11508  bool unhExc = (func[3] == 'U');
11509  DWORD code = (exc && exc->ExceptionRecord)? exc->ExceptionRecord->ExceptionCode : 0; //-V560
11510  void* addr = (exc && exc->ExceptionRecord)? exc->ExceptionRecord->ExceptionAddress : NULL; //-V560
11511 
11512  if (code == DBG_PRINTEXCEPTION_C ||
11513  code == DBG_PRINTEXCEPTION_WIDE_C ||
11514  code == DBG_THREAD_NAME ||
11515  (code == RPC_S_SERVER_UNAVAILABLE && !unhExc) ||
11516  (code == RPC_S_CALL_CANCELLED && !unhExc) ||
11517  (code == EXCEPTION_BREAKPOINT && IsDebuggerPresent()))
11518  return EXCEPTION_CONTINUE_SEARCH;
11519 
11520  ptrdiff_t dist = (uintptr_t) addr - (uintptr_t) IsBadReadPtr;
11521  if (0 <= dist && dist <= 256) {$6 return EXCEPTION_CONTINUE_SEARCH; }
11522 
11523  dist = (uintptr_t) addr - (uintptr_t) IsBadWritePtr;
11524  if (0 <= dist && dist <= 256) {$6 return EXCEPTION_CONTINUE_SEARCH; }
11525 
11526  _txSENumber = _txSENumber + 1;
11527  if (HIBYTE (HIWORD (code)) == 0xC0) _txSEFatalNumber = _txSEFatalNumber + 1;
11528 
11529  OutputDebugString ("\n");
11530  txOutputDebugPrintf ("%s - WARNING: #%ld: %s (code 0x%08lX, addr 0x%p) called\n",
11531  _TX_VERSION, _txSENumber, func, (unsigned long) code, addr);
11532 
11533 $6 if (*(unsigned long long*) _txDumpExceptionObjJmp)
11534  {
11535 $ longjmp (_txDumpExceptionObjJmp, 1); //-V2512
11536  }
11537 
11538  tx_fpreset();
11539 
11540  #if defined (_MSC_VER)
11541  if (code == EXCEPTION_STACK_OVERFLOW) {$ _resetstkoflw(); }
11542  #endif
11543 
11544 $ bool primaryException = !(func && exc) || !((unhExc && *_txDumpSE) || _TX_MSC__CXX_DETECT_RETHROW (exc->ExceptionRecord)); //-V560
11545 
11546 $ if (primaryException && exc) //-V560
11547  {
11548 $ unsigned err = GetLastError();
11549 
11550 $ const char* stackTrace = _txCaptureStackBackTrace (0, true, exc->ContextRecord, exc);
11551 
11552 $ _txDumpExceptionSEH (_txDumpSE, (intptr_t) sizeof (_txDumpSE) - 1, exc->ExceptionRecord, func);
11553 $ _tx_snprintf_s (_txTraceSE, (intptr_t) sizeof (_txTraceSE) - 1, "%s", stackTrace);
11554 
11555 $ static _tx_thread DWORD prevCode = 0;
11556 $ static _tx_thread void* prevAddr = NULL;
11557 
11558 $ if (code != prevCode && addr != prevAddr &&
11559  !strstr (_txDumpSE, "Объект исключения C++:"))
11560  {
11561 $ SetLastError (err);
11562 $ _TX_UNEXPECTED ("\v\b\t" "%s", _txDumpSE + 1);
11563 
11564 $ prevCode = code;
11565 $ prevAddr = addr;
11566  }
11567 
11568 $ SetLastError (err);
11569  }
11570 
11571 $ if (_txDumpSE[0] == '\a' ||
11572  _txSENumber >= _TX_EXCEPTIONS_LIMIT+0 ||
11573  _txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0)
11574  {
11575 $ _TX_UNEXPECTED ("\a\t" "%s"
11576  "С помощью функции _set_se_translator() вы можете сами обработать эту ошибку.",
11577  _txDumpSE + 1);
11578  }
11579 
11580 $ return EXCEPTION_CONTINUE_SEARCH;
11581  }
11582 
11583 //-----------------------------------------------------------------------------------------------------------------
11584 
11585 intptr_t _txDumpExceptionSEH (char what[], intptr_t size, const EXCEPTION_RECORD* exc, const char func[]) //-V2008
11586  {
11587 $6 assert (what);
11588 $ assert (size >= 0); //-V547
11589  assert (exc); if (!exc) {$ return 0; } //-V547
11590 $ assert (func);
11591 
11592 $ unsigned code = exc->ExceptionCode;
11593 $ void* addr = exc->ExceptionAddress;
11594 $ unsigned params = exc->NumberParameters;
11595 $ const ULONG_PTR* info = exc->ExceptionInformation;
11596 $ void* object = (params >= 2)? (void*) info[1] : NULL;
11597 
11598 $ char* s = what;
11599 
11600  #define PRINT_(...) s += _tx_snprintf_s (s, size-2 - (s-what), ##__VA_ARGS__)
11601 
11602 $ const char* sCode = NULL;
11603 $ const char* sDescr = NULL;
11604 
11605  #define GET_DESCR_(code, descr) case ((unsigned long) (code)): {$ sCode = #code; sDescr = descr; break; }
11606 
11607 $ switch (code)
11608  {
11609  GET_DESCR_ (EXCEPTION_ACCESS_VIOLATION, " " "Нарушение доступа к памяти.")
11610  GET_DESCR_ (EXCEPTION_ILLEGAL_INSTRUCTION, " " "Недопустимая операция.")
11611  GET_DESCR_ (EXCEPTION_PRIV_INSTRUCTION, " " "Привилегированная операция.")
11612  GET_DESCR_ (EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "\a" "Выходза границы массива. Ставьте ассерты!") GET_DESCR_ (EXCEPTION_BREAKPOINT, "\a" "Достигнута точка останова. Удачи в отладке!") GET_DESCR_ (EXCEPTION_DATATYPE_MISALIGNMENT, "\a" "Нарушение выравнивания данных.") GET_DESCR_ (EXCEPTION_INVALID_DISPOSITION, "\a" "Обработчик исключения возвратил неверное значение.") GET_DESCR_ (EXCEPTION_IN_PAGE_ERROR, "\a" "Невозможно загрузить нужную страницу памяти.") GET_DESCR_ (EXCEPTION_NONCONTINUABLE_EXCEPTION, "\a" "Продолжение выполнения невозможно.") GET_DESCR_ (EXCEPTION_SINGLE_STEP, "\a" "Выполнена инструкция машинного кода. Одна штука.") GET_DESCR_ (EXCEPTION_STACK_OVERFLOW, "\a" "Ю-ху! Переполнение стека!") GET_DESCR_ (EXCEPTION_GUARD_PAGE, "\a" "Попытка доступа к защищенной странице памяти.") GET_DESCR_ (EXCEPTION_INVALID_HANDLE, "\a" "Неверный или уже закрытый дескриптор.") GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.") GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стека при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11613  GET_DESCR_ (EXCEPTION_BREAKPOINT, "\a" "Достигнута точкаостанова. Удачи в отладке!") GET_DESCR_ (EXCEPTION_DATATYPE_MISALIGNMENT, "\a" "Нарушение выравнивания данных.") GET_DESCR_ (EXCEPTION_INVALID_DISPOSITION, "\a" "Обработчик исключения возвратил неверное значение.") GET_DESCR_ (EXCEPTION_IN_PAGE_ERROR, "\a" "Невозможно загрузить нужную страницу памяти.") GET_DESCR_ (EXCEPTION_NONCONTINUABLE_EXCEPTION, "\a" "Продолжение выполнения невозможно.") GET_DESCR_ (EXCEPTION_SINGLE_STEP, "\a" "Выполнена инструкция машинного кода. Одна штука.") GET_DESCR_ (EXCEPTION_STACK_OVERFLOW, "\a" "Ю-ху! Переполнение стека!") GET_DESCR_ (EXCEPTION_GUARD_PAGE, "\a" "Попытка доступа к защищенной странице памяти.") GET_DESCR_ (EXCEPTION_INVALID_HANDLE, "\a" "Неверный или уже закрытый дескриптор.") GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.") GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стека при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11614  GET_DESCR_ (EXCEPTION_DATATYPE_MISALIGNMENT, "\a" "Нарушениевыравнивания данных.") GET_DESCR_ (EXCEPTION_INVALID_DISPOSITION, "\a" "Обработчик исключения возвратил неверное значение.") GET_DESCR_ (EXCEPTION_IN_PAGE_ERROR, "\a" "Невозможно загрузить нужную страницу памяти.") GET_DESCR_ (EXCEPTION_NONCONTINUABLE_EXCEPTION, "\a" "Продолжение выполнения невозможно.") GET_DESCR_ (EXCEPTION_SINGLE_STEP, "\a" "Выполнена инструкция машинного кода. Одна штука.") GET_DESCR_ (EXCEPTION_STACK_OVERFLOW, "\a" "Ю-ху! Переполнение стека!") GET_DESCR_ (EXCEPTION_GUARD_PAGE, "\a" "Попытка доступа к защищенной странице памяти.") GET_DESCR_ (EXCEPTION_INVALID_HANDLE, "\a" "Неверный или уже закрытый дескриптор.") GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.") GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стека при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11615  GET_DESCR_ (EXCEPTION_INVALID_DISPOSITION, "\a" "Обработчик исключения возвратилневерное значение.") GET_DESCR_ (EXCEPTION_IN_PAGE_ERROR, "\a" "Невозможно загрузить нужную страницу памяти.") GET_DESCR_ (EXCEPTION_NONCONTINUABLE_EXCEPTION, "\a" "Продолжение выполнения невозможно.") GET_DESCR_ (EXCEPTION_SINGLE_STEP, "\a" "Выполнена инструкция машинного кода. Одна штука.") GET_DESCR_ (EXCEPTION_STACK_OVERFLOW, "\a" "Ю-ху! Переполнение стека!") GET_DESCR_ (EXCEPTION_GUARD_PAGE, "\a" "Попытка доступа к защищенной странице памяти.") GET_DESCR_ (EXCEPTION_INVALID_HANDLE, "\a" "Неверный или уже закрытый дескриптор.") GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.") GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стека при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11616  GET_DESCR_ (EXCEPTION_IN_PAGE_ERROR, "\a" "Невозможно загрузитьнужную страницу памяти.") GET_DESCR_ (EXCEPTION_NONCONTINUABLE_EXCEPTION, "\a" "Продолжение выполнения невозможно.") GET_DESCR_ (EXCEPTION_SINGLE_STEP, "\a" "Выполнена инструкция машинного кода. Одна штука.") GET_DESCR_ (EXCEPTION_STACK_OVERFLOW, "\a" "Ю-ху! Переполнение стека!") GET_DESCR_ (EXCEPTION_GUARD_PAGE, "\a" "Попытка доступа к защищенной странице памяти.") GET_DESCR_ (EXCEPTION_INVALID_HANDLE, "\a" "Неверный или уже закрытый дескриптор.") GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.") GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стека при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11617  GET_DESCR_ (EXCEPTION_NONCONTINUABLE_EXCEPTION, "\a" "Продолжениевыполнения невозможно.") GET_DESCR_ (EXCEPTION_SINGLE_STEP, "\a" "Выполнена инструкция машинного кода. Одна штука.") GET_DESCR_ (EXCEPTION_STACK_OVERFLOW, "\a" "Ю-ху! Переполнение стека!") GET_DESCR_ (EXCEPTION_GUARD_PAGE, "\a" "Попытка доступа к защищенной странице памяти.") GET_DESCR_ (EXCEPTION_INVALID_HANDLE, "\a" "Неверный или уже закрытый дескриптор.") GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.") GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стека при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11618  GET_DESCR_ (EXCEPTION_SINGLE_STEP, "\a" "Выполненаинструкция машинного кода. Одна штука.") GET_DESCR_ (EXCEPTION_STACK_OVERFLOW, "\a" "Ю-ху! Переполнение стека!") GET_DESCR_ (EXCEPTION_GUARD_PAGE, "\a" "Попытка доступа к защищенной странице памяти.") GET_DESCR_ (EXCEPTION_INVALID_HANDLE, "\a" "Неверный или уже закрытый дескриптор.") GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.") GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стека при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11619  GET_DESCR_ (EXCEPTION_STACK_OVERFLOW, "\a" "Юху! Переполнение стека!") GET_DESCR_ (EXCEPTION_GUARD_PAGE, "\a" "Попытка доступа к защищенной странице памяти.") GET_DESCR_ (EXCEPTION_INVALID_HANDLE, "\a" "Неверный или уже закрытый дескриптор.") GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.") GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стека при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11620  GET_DESCR_ (EXCEPTION_GUARD_PAGE, "\a" "Попыткадоступа к защищенной странице памяти.") GET_DESCR_ (EXCEPTION_INVALID_HANDLE, "\a" "Неверный или уже закрытый дескриптор.") GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.") GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стека при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11621  GET_DESCR_ (EXCEPTION_INVALID_HANDLE, "\a" "Неверный илиуже закрытый дескриптор.") GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.") GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стека при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11622  GET_DESCR_ (STATUS_POSSIBLE_DEADLOCK, "\a" "Возможно, взаимная блокировка ресурсов.")
11623 
11624  GET_DESCR_ (EXCEPTION_FLT_STACK_CHECK, "\a" "Ошибка стекапри операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числа с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11625  GET_DESCR_ (EXCEPTION_FLT_DENORMAL_OPERAND, " " "Денормализация числас плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Деление на ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11626  GET_DESCR_ (EXCEPTION_FLT_DIVIDE_BY_ZERO, " " "Делениена ноль при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результат при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11627  GET_DESCR_ (EXCEPTION_FLT_INEXACT_RESULT, " " "Неточный результатпри операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11628  GET_DESCR_ (EXCEPTION_FLT_INVALID_OPERATION, " " "Недопустимая операция сплавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение при операции с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11629  GET_DESCR_ (EXCEPTION_FLT_OVERFLOW, " " "Переполнение приоперации с плавающей точкой.") GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости при операции с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11630  GET_DESCR_ (EXCEPTION_FLT_UNDERFLOW, " " "Потеря значимости приоперации с плавающей точкой.") GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественные ошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11631  GET_DESCR_ (STATUS_FLOAT_MULTIPLE_FAULTS, " " "Множественныеошибки с плавающей точкой.") GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленное деление на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11632 
11633  GET_DESCR_ (EXCEPTION_INT_DIVIDE_BY_ZERO, "\a" "Целочисленноеделение на ноль.") GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение при целочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11634  GET_DESCR_ (EXCEPTION_INT_OVERFLOW, "\a" "Переполнение прицелочисленной операции.") GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой среды исполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11635 
11636  GET_DESCR_ (EXCEPTION_CLR_FAILURE, "\a" "Сбой средыисполнения (CLR).") GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стекового буфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11637  GET_DESCR_ (STATUS_STACK_BUFFER_OVERRUN, "\a" "Переполнение стековогобуфера!") GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот раз из ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11638  GET_DESCR_ (STATUS_ASSERTION_FAILURE, "\a" "Сработал assert. На этот разиз ядра.") GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точка останова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11639  GET_DESCR_ (STATUS_WX86_BREAKPOINT, "\a" "Точкаостанова подсистемы эмуляции x86.") GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестный интерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11640  GET_DESCR_ (RPC_S_UNKNOWN_IF, "\a" "Неизвестныйинтерфейс удаленного вызова процедур (RPC).") GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.") GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил поток сознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11641  GET_DESCR_ (RPC_S_SERVER_UNAVAILABLE, "\a" "Сервер удаленного вызова процедур (RPC) недоступен.")
11642  GET_DESCR_ (DBG_TERMINATE_THREAD, "\a" "Отладчик завершил потоксознания.") GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс.") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11643  GET_DESCR_ (DBG_TERMINATE_PROCESS, "\a" "Отладчик завершил процесс") GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получил сигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11644  GET_DESCR_ (DBG_CONTROL_C, "\a" "Отладчик получилсигнал прерывания Control+C.") GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получил сигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11645  GET_DESCR_ (DBG_CONTROL_BREAK, "\a" "Отладчик получилсигнал прерывания Control+Break.") GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получил указание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11646  GET_DESCR_ (DBG_THREAD_NAME, " " "Отладчик получилуказание дать потоку имя.") GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11647  GET_DESCR_ (DBG_PRINTEXCEPTION_C, " " "Отладчик вывелисключение по CTRL+C (OutputDebugStringA).") GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывел исключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11648  GET_DESCR_ (DBG_PRINTEXCEPTION_WIDE_C, " " "Отладчик вывелисключение по CTRL+C (OutputDebugStringW).") GET_DESCR_ (EXCEPTION_CPP_MSC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11649 
11650  GET_DESCR_ (EXCEPTION_CPP_MSC, " " "ИсключениеС++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC, " " "Исключение С++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11651  GET_DESCR_ (EXCEPTION_CPP_GCC, " " "ИсключениеС++, вызванное оператором throw.") GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "Исключение С++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11652  GET_DESCR_ (EXCEPTION_CPP_GCC_UNWIND, " " "ИсключениеС++, вызванное во время раскрутки стека (rethrow?).") GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "Исключение С++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11653  GET_DESCR_ (EXCEPTION_CPP_GCC_FORCED, " " "ИсключениеС++, вызванное нарушением магии.") GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Это скомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11654  GET_DESCR_ (EXCEPTION_CPP_BORLAND_BUILDER, "\a" "Этоскомпилилось под Билдер? O_O") GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Это же С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11655  GET_DESCR_ (EXCEPTION_CPP_BORLAND_DELPHI, "\a" "Этоже С++. Как это вышло?") default: $ break; } #undef GET_DESCR_ $ if (sDescr) { $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode); } else { $ PRINT_ ("\a#%ld: ", _txSENumber); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ ("\r\r"); } $ PRINT_ (" (0x%X) при выполнении кода по адресу", code); $ PRINT_ ((addr? " 0x%p" : " NULL"), addr); $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); } $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name); $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber); $ if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (". Попытка "); $ unsigned long op = 0xBADC0DE; $ const char* sOp = "(действие не указано)"; $ if (params >= 1) { $ switch (op = (unsigned long) info[0]) //-V202 { case 0: $ sOp = "прочесть данные"; break; case 1: $ sOp = "записать данные"; break; case 8: $ sOp = "исполнить код"; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
11656 
11657  default: $ break;
11658  }
11659 
11660  #undef GET_DESCR_
11661 
11662 $ if (sDescr)
11663  {
11664 $ PRINT_ ("%s\n\n" "#%ld: Исключение %s", sDescr, _txSENumber, sCode);
11665  }
11666  else
11667  {
11668 $ PRINT_ ("\a#%ld: ", _txSENumber);
11669 $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102
11670  GetModuleHandle ("NTDLL.DLL"), code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
11671  s, (DWORD) (size - (s-what)), NULL) - 2; //-V202
11672 $ PRINT_ ("\r\r");
11673  }
11674 
11675 $ PRINT_ (" (0x%X) при выполнении кода по адресу", code);
11676 $ PRINT_ ((addr? " 0x%p" : " NULL"), addr);
11677 
11678 $ Win32::SYMBOL_INFO* sym = NULL;
11679 $ Win32::IMAGEHLP_LINE64* line = NULL;
11680 
11681  if (addr) {$ _txSymGetFromAddr (addr, &sym, &line); }
11682 
11683 $ if (sym && *sym->Name) PRINT_ (" в функции %s()", sym->Name);
11684 $ if (line && line->FileName && *line->FileName) PRINT_ (" в файле %s на строке %u", line->FileName, (unsigned) line->LineNumber);
11685 
11686 $ if (code == EXCEPTION_ACCESS_VIOLATION ||
11687  code == EXCEPTION_IN_PAGE_ERROR)
11688  {
11689 $ PRINT_ (". Попытка ");
11690 
11691 $ unsigned long op = 0xBADC0DE;
11692 $ const char* sOp = "(действие не указано)";
11693 
11694 $ if (params >= 1)
11695  {
11696 $ switch (op = (unsigned long) info[0]) //-V202
11697  {
11698  case 0: $ sOp = "прочесть данные"; break;
11699  case 1: $ sOp = "записать данные"; break;
11700  case 8: $ sOp = "исполнить код; break; default: $ sOp = "совершить операцию 0x%lX"; break; } } $ PRINT_ (sOp, op); $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048 else {$ PRINT_ (" (адрес не указан)"); } $ if (code == EXCEPTION_IN_PAGE_ERROR) { $ PRINT_ (", ошибка ввода-вывода:"); $ if (params >= 3) { $ unsigned long ntstatus = (unsigned long) info[2]; //-V202 $ PRINT_ (" 0x%lX (", ntstatus); $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (size - (s-what)), NULL) - 2; //-V202 $ PRINT_ (")"); } else {$ PRINT_ (" (не указана)"); } } } $ HMODULE module = NULL; $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module)); $ if (module) { $ static char sModule [MAX_PATH] = ""; $ int ok = GetModuleFileName (module, sModule, sizeof (sModule)); $ char* ext = (ok? strrchr (sModule, '.') : NULL); $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule)); if (ok) {$ PRINT_ (" в модуле %s", sModule); } else {$ PRINT_ (" в модуле 0x%p", (void*) module); } } $ PRINT_ ("."); $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); } $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0) {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); } $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func); $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE) {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); } $ if (exc->ExceptionRecord) { $ PRINT_ ("\n\n" "Причина:" "\n\n"); $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func); } $ if (code == EXCEPTION_CPP_GCC || code == EXCEPTION_CPP_GCC_UNWIND || code == EXCEPTION_CPP_GCC_FORCED || code == EXCEPTION_CPP_MSC) { $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info); } #undef PRINT_ $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n"); $ return s - what; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionCPP (char what[], intptr_t size, unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/) { $6 assert (what); $ assert (size >= 0); //-V547 $ char* s = what; $ switch (code) { #if defined (_GCC_VER) case EXCEPTION_CPP_GCC: case EXCEPTION_CPP_GCC_UNWIND: case EXCEPTION_CPP_GCC_FORCED: { // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below // and figure above near ABI::__cxa_exception definition in this file $ const std::type_info* type = NULL; $ void* object = NULL; $ if (params >= 1) { $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0]; $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1; $ type = cxa_exception->exceptionType; $ object = cxa_exception + 1; } $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type); } $ break; case 0: // Not called within SEH chain { // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc using namespace abi; $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions; $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above { $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1; } $ if (cxa_exception) { $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type()); $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType); } } $ break; #elif defined (_MSC_VER) case EXCEPTION_CPP_MSC: { // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 // [2] http://www.openrce.org/articles/full_view/21 // [3] http://www.openrce.org/articles/full_view/23 // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf $ const std::type_info* type = NULL; $ void* object = (params >= 2)? (void*) info[1] : NULL; $ size_t szObj = 0; $ if (params >= 3 && (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 || info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 || info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1)) { $ auto throwInfo = (const Win32::ThrowInfo*) info[2]; $ if (throwInfo && throwInfo->pCatchableTypeArray) { $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112 #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) ) $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray); $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]); $ type = RVA_(const std::type_info*, cType->pType); $ szObj = cType->sizeOrOffset; //-V101 #undef RVA_ } } $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type); } break; case 0: // Not called within SEH chain // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC: // // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp // // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception. // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp // and http://msdn.microsoft.com/en-us/library/ff730818.aspx. // // So _txDumpSE information should have been recorded during previous call. Now do nothing. $ break; #endif default: $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code); $ break; } $ while (s > what && s[-1] == '\n') s--; $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n"); $ return (s - what); } //----------------------------------------------------------------------------------------------------------------- intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008 { $6 assert (what); $ assert (size > 0); //-V547 $ static char* s = NULL; s = what; $ static size_t szObj = 0; szObj = sizeObj; #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__) $ PRINT_ ("\n\n" "Объект исключения C++:"); $ const char* mangledName = (type)? type->name() : NULL; $ char* typeName = NULL; $ int err = 1; #if defined (_GCC_VER) $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); #endif $ const char* name = (!err && typeName)? typeName : mangledName; //-V560 $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0)) {$ name = "std::string"; } $ if (name && (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 || strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 || strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0)) {$ name = "std::string*"; } if (name) {$ PRINT_ (" %s", name); } #if defined (_GCC_VER) $ free (typeName); #endif $ err = 0; $ if (mangledName) { if (_txSetJmp()) { #define PRINT_VAL_(fmt, typ, ...) \ else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \ else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } #define NO_ if (false) ; PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517 PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206 PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206 PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206 PRINT_VAL_ ("%s", std::string, .c_str()) //-V206 else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object)) { $ PRINT_ (", what(): \"%s\"", e->what()); } else {$ err = 1; } } else {$ err = 2; } } $ _txClearJmp(); $ if (err && object && szObj) { $ const unsigned char* buf = (const unsigned char*) object; $ if (szObj >= 64) szObj = 64; $ PRINT_ (", дамп: ["); $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' ); $ PRINT_ ("]"); $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]); $ err = 0; } $ if (err) {$ PRINT_ (" = ??"); } $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560 #undef PRINT_VAL_ #undef PRINT_ #undef NO_ $ return s - what; } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Stack trace and debug info access //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/, CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/, HANDLE thread /*= GetCurrentThread()*/) { $6 const int maxFrames = 62; // MS says: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ static void* capture [maxFrames] = {}; $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread); $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__) $ for (int i = 0, n = 0; i < frames; i++) //-V2530 { $ void* addr = capture[i]; $ Win32::SYMBOL_INFO* sym = NULL; $ Win32::IMAGEHLP_LINE64* line = NULL; $ const char* module = NULL; $ const char* source = NULL; $ bool inTX = false; if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); } if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566 $ int nl = 0; $ while (s > trace && s[-1] == '\n') { s--; nl++; } #if !defined (_TX_FULL_STACKTRACE) $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber)))) {$ continue; } #endif $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr); $ n++; if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; } if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; } if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566 if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); } if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); } if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); } if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); } if (source) {$ PRINT_ (":\n\n" "%s\n", source); } if (sym && strcmp (sym->Name , "main") == 0) {$ break; } } #if defined (_MSC_VER) #pragma warning (push) #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s' #endif $ while (s > trace && s[-1] == '\n') s--; $ *s = 0; #if defined (_MSC_VER) #pragma warning (pop) // Using possibly uninitialized memory '*s' #endif #undef PRINT_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); #if !defined (_TX_NO_MINIDUMP) $ _txCreateMiniDump (exc); #endif $ return trace; } //----------------------------------------------------------------------------------------------------------------- // Stack WALKING if the program is DEAD. Dead, Carl! int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/, HANDLE thread /* = GetCurrentThread()*/) { $6 namespace MinGW = Win32::MinGW; $ assert (capture); $ HANDLE process = GetCurrentProcess(); $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId()); $ CONTEXT ctx = {}; $ ctx.ContextFlags |= CONTEXT_FULL; $ int isWow64 = 0; $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64); else {$ return -1; } $ if (context) { $ ctx = *context; } else { $ if (thisThread) { $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx)); } else { $ SuspendThread (thread); //-V720 $ ctx.ContextFlags = CONTEXT_ALL; $ bool ok = !!GetThreadContext (thread, &ctx); $ if (!ok) { $ ResumeThread (thread); $ return -1; } } } $ Win32::STACKFRAME64 frame = {}; $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat; $ int cpu = 0; #if defined (_WIN64) $ if (isWow64) { $ Win32::WOW64_CONTEXT wow64ctx = {}; $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL; $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE, { // while EXIT_PROCESS_DEBUG_EVENT if (!thisThread) {$ ResumeThread (thread); } $ return 0; } $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = wow64ctx.Eip; $ frame.AddrStack.Offset = wow64ctx.Esp; $ frame.AddrFrame.Offset = wow64ctx.Ebp; } else { $ cpu = IMAGE_FILE_MACHINE_AMD64; $ frame.AddrPC .Offset = ctx.Rip; $ frame.AddrStack.Offset = ctx.Rbp; $ frame.AddrFrame.Offset = ctx.Rsp; } #else { $ cpu = IMAGE_FILE_MACHINE_I386; $ frame.AddrPC .Offset = ctx.Eip; $ frame.AddrStack.Offset = ctx.Ebp; $ frame.AddrFrame.Offset = ctx.Esp; } #endif $ assert (cpu); if (_txSetJmp()) { $ _txSymGetFromAddr ((void*) 1); //-V566 } $ _txClearJmp(); $ int frames = -1; $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530 { $ DWORD64 prev = frame.AddrStack.Offset; // Я злой и страшный серый walk. Я в поросятах знаю talk. if (!_txSetJmp()) {$ break; } #if defined (_GCC_VER) if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; } #elif defined (_MSC_VER) $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL, Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; } #else #error _GCC_VER / _MSC_VER not defined #endif if (frames < 0) {$ continue; } $ void* addr = (void*) frame.AddrPC.Offset; if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame $ assert (0 <= frames && frames < (int) szCapture); //-V202 $ capture[frames] = addr; //-V108 } $ _txClearJmp(); if (!thisThread) {$ ResumeThread (thread); } $ return frames; } // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl //----------------------------------------------------------------------------------------------------------------- bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/, Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/, const char** source /*= NULL*/, int context /*= 2*/) { $7 static HANDLE process = NULL; #if defined (_GCC_VER) #define LIB_ Win32::MinGW #elif defined (_MSC_VER) #define LIB_ Win32 #else #error _GCC_VER / _MSC_VER not defined #endif $ if (!process && addr) { $ process = GetCurrentProcess(); $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS; $ _TX_CALL (LIB_::SymSetOptions, (options)); $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true)); } $ static DWORD64 mod = 0; $ if (module) { $ static char sMod [MAX_PATH] = ""; $ memset (sMod, 0, sizeof (sMod)); $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr)); $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH); $ char* ext = strrchr (sMod, '.'); if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); } $ *module = sMod; } $ static char buffer [_TX_BUFSIZE] = ""; $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032 $ if (symbol) { $ memset (buffer, 0, sizeof (buffer)); $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1; $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO); $ unsigned long long ofs = 0; $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym)); if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; } $ *symbol = sym; } $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) }; $ if (line) { $ memset (&line64, 0, sizeof (line64)); $ DWORD ofs = 0; $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64)); $ *line = &line64; } $ if (source) { $ static char buf [_TX_BUFSIZE] = ""; $ memset (buf, 0, sizeof (buf)); $ if (line64.FileName && line64.LineNumber) { $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName, (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber); $ *source = buf; } if (!*source || !**source) {$ *source = NULL; } } $ if (!addr && process) { $ _TX_CALL (LIB_::SymCleanup, (process)); $ process = NULL; } #if (_GCC_VER == 481) #pragma GCC diagnostic push #pragma GCC system_header #endif $ if (symbol) { $ if (strstr (sym->Name, "::TX::") || (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) || (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) || strncmp (sym->Name, "_tx_", 4) == 0 || //-V112 strncmp (sym->Name, "tx_", 3) == 0) { $ return true; } #if (_GCC_VER == 481) #pragma GCC diagnostic pop #endif $ if (!line || !line64.FileName) return false; $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1); $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) && (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\'); } #undef LIB_ $ return false; } //----------------------------------------------------------------------------------------------------------------- intptr_t _txReadSource (char buf[], intptr_t size, const char file[], int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/) { $7 assert (buf); if (!file || !*file) {$ return 0; } if (linStart < 1) {$ linStart = 1; } if (linEnd == -1) {$ linEnd = INT_MAX; } $ FILE* f = NULL; $ fopen_s (&f, file, "r"); if (!f) {$ return 0; } $ int n = 1; while (!feof (f)) { if (n >= linStart) {$ break; } while (!feof (f) && fgetc (f) != '\n') ; n++; } $ char* s = buf; #define SZ_ ( size - 3 - (s - buf) ) $ while (!feof (f) && SZ_ > 0) { if (n > linEnd || _txNOP (SZ_) < 0) {$ break; } if (linMark != INT_MIN) {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); } $ int c = 0; $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c; if (c == EOF) {$ s--; } if (SZ_ > 0) {$ *s++ = '\n'; } $ n++; } if (n <= linEnd && SZ_ <= 0) {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); } #undef SZ_ $ fclose (f); if (s > buf && s[-1] == '\n') {$ s--; } $ *s = 0; $ return (s - buf); } //----------------------------------------------------------------------------------------------------------------- const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/) { $6 const int maxFrames = 62; // TX says too: < 63 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = ""; if (framesToSkip == -1) {$ return trace; } $ memset (trace, 0, sizeof (trace)); $ char* s = trace; #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) ) $ const _txLoc* loc = &_txLoc::Cur; for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; } $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev) { if (i < 0) {$ continue; } if (loc->func || loc->file || loc->line) { $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""), i, loc->func, loc->file, loc->line); $ if (readSource) { $ s += _tx_snprintf_s (s, SZ_, ":\n\n"); $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line); } } } #undef SZ_ $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), ""); $ return trace; } //----------------------------------------------------------------------------------------------------------------- bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/) { $6 static char dumpName[MAX_PATH] = ""; if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); } $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!file || file == INVALID_HANDLE_VALUE) {$ return false; } $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false }; $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory); $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type, ((exc)? &excInfo : NULL), NULL, NULL)); $ CloseHandle (file); if (ok) {$ return true; } else {$ return false; } } #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Errors reporting //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008 { _txErrors = _txErrors + 1; DWORD winErr = GetLastError(); int crtErr = errno; #if !defined (__CYGWIN__) unsigned long dosErr = _doserrno; #else unsigned long dosErr = 0; #endif unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ()); unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError; unsigned threadId = GetCurrentThreadId(); enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 }; unsigned options = 0; for (; msg && *msg; msg++) { if (*msg == '\a') options |= isFatal; else if (*msg == '\v') options |= isWarning; else if (*msg == '\b') options |= noMsgBox; else if (*msg == '\f') options |= fmtOnly; else if (*msg == '\t') options |= traceSE; else break; } const char* stkTrace = NULL; const char* txTrace = NULL; (void) txTrace; if (!(options & fmtOnly)) { stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true); txTrace = _txCaptureStackBackTraceTX (0, true); } static char what[_TX_BIGBUFSIZE*10] = ""; static char str [_TX_BIGBUFSIZE] = ""; char *s = what; #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__) PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" : (options & isFatal)? "соболезнует..." : "сообщает:")); PRINT_ ("Программа: %s", txGetModuleFileName()); if (file) PRINT_ (", файл: %s", file); if (line) PRINT_ (", строка: %d", line); if (func) PRINT_ (", функция: %s", func); PRINT_ (",\n\n"); if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение" : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки; break;
11701  default: $ sOp = "совершить операцию 0x%lX"; break;
11702  }
11703  }
11704 
11705 $ PRINT_ (sOp, op);
11706 
11707 $ if (params >= 2) {$ PRINT_ ((object? " по адресу 0x%p" : " по адресу NULL"), object); } //-V1048
11708  else {$ PRINT_ (" (адрес не указан)"); }
11709 
11710 $ if (code == EXCEPTION_IN_PAGE_ERROR)
11711  {
11712 $ PRINT_ (", ошибка ввода-вывода:");
11713 
11714 $ if (params >= 3)
11715  {
11716 $ unsigned long ntstatus = (unsigned long) info[2]; //-V202
11717 
11718 $ PRINT_ (" 0x%lX (", ntstatus);
11719 
11720 $ s += FormatMessage (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102
11721  GetModuleHandle ("NTDLL.DLL"), ntstatus, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
11722  s, (DWORD) (size - (s-what)), NULL) - 2; //-V202
11723 $ PRINT_ (")");
11724  }
11725  else
11726  {$ PRINT_ (" (не указана)"); }
11727  }
11728  }
11729 
11730 $ HMODULE module = NULL;
11731 $ _TX_CALL (Win32::GetModuleHandleEx, (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*) addr, &module));
11732 
11733 $ if (module)
11734  {
11735 $ static char sModule [MAX_PATH] = "";
11736 $ int ok = GetModuleFileName (module, sModule, sizeof (sModule));
11737 
11738 $ char* ext = (ok? strrchr (sModule, '.') : NULL);
11739 $ if (ext) _strlwr_s (ext, sizeof (sModule) - 1 - (ext - sModule));
11740 
11741  if (ok) {$ PRINT_ (" в модуле %s", sModule); }
11742  else {$ PRINT_ (" в модуле 0x%p", (void*) module); }
11743  }
11744 
11745 $ PRINT_ (".");
11746 
11747 $ if (_txSENumber >= _TX_EXCEPTIONS_LIMIT+0)
11748  {$ PRINT_ (" Дополнительно, превышен лимит исключений _TX_EXCEPTIONS_LIMIT (%d).", _TX_EXCEPTIONS_LIMIT+0); }
11749 
11750 $ if (_txSEFatalNumber >= _TX_FATAL_EXCEPTIONS_LIMIT+0)
11751  {$ PRINT_ (" Также превышен лимит фатальных исключений _TX_FATAL_EXCEPTIONS_LIMIT (%d).", _TX_FATAL_EXCEPTIONS_LIMIT+0); }
11752 
11753 $ PRINT_ (" Спасибо %s(), что сообщил. Люблю его <3", func);
11754 
11755 $ if (exc->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
11756  {$ PRINT_ ("\n\n" "Ой, всё (EXCEPTION_NONCONTINUABLE)."); }
11757 
11758 $ if (exc->ExceptionRecord)
11759  {
11760 $ PRINT_ ("\n\n" "Причина:" "\n\n");
11761 $ s += _txDumpExceptionSEH (s, size - (s-what), exc->ExceptionRecord, func);
11762  }
11763 
11764 $ if (code == EXCEPTION_CPP_GCC ||
11765  code == EXCEPTION_CPP_GCC_UNWIND ||
11766  code == EXCEPTION_CPP_GCC_FORCED ||
11767  code == EXCEPTION_CPP_MSC)
11768  {
11769 $ s += _txDumpExceptionCPP (s, size - (s-what), code, params, info);
11770  }
11771 
11772  #undef PRINT_
11773 
11774 $ while (s > what && s[-1] == '\n') s--;
11775 $ if (s > what) s += _tx_snprintf_s (s, size - (s-what), "\n\n");
11776 
11777 $ return s - what;
11778  }
11779 
11780 //-----------------------------------------------------------------------------------------------------------------
11781 
11782 intptr_t _txDumpExceptionCPP (char what[], intptr_t size,
11783  unsigned code /*= 0*/, unsigned params /*= 0*/, const ULONG_PTR info[] /*= NULL*/)
11784  {
11785 $6 assert (what);
11786 $ assert (size >= 0); //-V547
11787 
11788 $ char* s = what;
11789 
11790 $ switch (code)
11791  {
11792  #if defined (_GCC_VER)
11793 
11794  case EXCEPTION_CPP_GCC:
11795  case EXCEPTION_CPP_GCC_UNWIND:
11796  case EXCEPTION_CPP_GCC_FORCED:
11797  {
11798  // See: [1] http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp
11799  // [2] http://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-seh.c, lines 51-55 and below
11800  // [3] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_throw.cc, __cxa_throw, line 59 and below
11801  // [4] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/unwind-cxx.h, __cxa_exception, line 58 and below
11802  // and figure above near ABI::__cxa_exception definition in this file
11803 
11804 $ const std::type_info* type = NULL;
11805 $ void* object = NULL;
11806 
11807 $ if (params >= 1)
11808  {
11809 $ _Unwind_Exception* unwind_exception = (_Unwind_Exception*) info[0];
11810 $ ABI::__cxa_exception* cxa_exception = (ABI::__cxa_exception*) (unwind_exception + 1) - 1;
11811 
11812 $ type = cxa_exception->exceptionType;
11813 $ object = cxa_exception + 1;
11814  }
11815 
11816 $ s += _txDumpExceptionObj (s, size - (s-what), object, 0, type);
11817  }
11818 $ break;
11819 
11820  case 0: // Not called within SEH chain
11821  {
11822  // From: [1] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_type.cc
11823  // [2] http://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/vterminate.cc
11824 
11825  using namespace abi;
11826 
11827 $ ABI::__cxa_exception* cxa_exception = __cxa_get_globals() -> caughtExceptions;
11828 
11829 $ if (cxa_exception && (cxa_exception->unwindHeader.exception_class & 1)) // Dependent exception, case B, see pic above
11830  {
11831 $ cxa_exception = (((ABI::__cxa_exception*) (&cxa_exception->unwindHeader + 1) - 1) -> primaryException) - 1;
11832  }
11833 
11834 $ if (cxa_exception)
11835  {
11836 $ verify (cxa_exception->exceptionType == abi::__cxa_current_exception_type());
11837 
11838 $ s += _txDumpExceptionObj (s, size, cxa_exception + 1, 0, cxa_exception->exceptionType);
11839  }
11840  }
11841 $ break;
11842 
11843  #elif defined (_MSC_VER)
11844 
11845  case EXCEPTION_CPP_MSC:
11846  {
11847  // See [1] http://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273
11848  // [2] http://www.openrce.org/articles/full_view/21
11849  // [3] http://www.openrce.org/articles/full_view/23
11850  // [4] http://yurichev.com/mirrors/RE/Recon-2012-Skochinsky-Compiler-Internals.pdf
11851 
11852 $ const std::type_info* type = NULL;
11853 $ void* object = (params >= 2)? (void*) info[1] : NULL;
11854 $ size_t szObj = 0;
11855 
11856 $ if (params >= 3 &&
11857  (info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER1 ||
11858  info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER2 ||
11859  info[0] == EXCEPTION_CPP_MSC_EH_MAGIC_NUMBER3 ||
11860  info[0] == EXCEPTION_CPP_MSC_EH_PURE_MAGIC_NUMBER1))
11861  {
11862 $ auto throwInfo = (const Win32::ThrowInfo*) info[2];
11863 
11864 $ if (throwInfo && throwInfo->pCatchableTypeArray)
11865  {
11866 $ HMODULE module = (params >= 4)? (HMODULE) info[3] : NULL; //-V112
11867 
11868  #define RVA_(type, addr) ( (type) ((uintptr_t) module + (uintptr_t) (addr)) )
11869 
11870 $ const Win32::CatchableTypeArray* cArray = RVA_(const Win32::CatchableTypeArray*, throwInfo->pCatchableTypeArray);
11871 $ const Win32::CatchableType* cType = RVA_(const Win32::CatchableType*, cArray->arrayOfCatchableTypes[0]);
11872 
11873 $ type = RVA_(const std::type_info*, cType->pType);
11874 $ szObj = cType->sizeOrOffset; //-V101
11875 
11876  #undef RVA_
11877  }
11878  }
11879 
11880 $ s += _txDumpExceptionObj (s, size - (s-what), object, szObj, type);
11881  }
11882  break;
11883 
11884  case 0: // Not called within SEH chain
11885 
11886  // signal() handlers or unexpected()/terminate() are called after Vectored Exception in MSC:
11887  //
11888  // terminate() is called by __scrt_unhandled_exception_filter() in case of MSC exception.
11889  // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\utility_desktop.cpp
11890  //
11891  // signal() handlers are called by _seh_filter_exe(), which is called by _mainCRTStartup() in case of exception.
11892  // See C:\Bin\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\mcrtexe.cpp
11893  // and C:\Bin\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\exception_filter.cpp
11894  // and http://msdn.microsoft.com/en-us/library/ff730818.aspx.
11895  //
11896  // So _txDumpSE information should have been recorded during previous call. Now do nothing.
11897 
11898 $ break;
11899 
11900  #endif
11901 
11902  default:
11903 $ txOutputDebugPrintf ("ERROR: Wrong call to %s: Unknown exception code 0x%08X\n", __TX_FUNCTION__, code);
11904 $ break;
11905  }
11906 
11907 $ while (s > what && s[-1] == '\n') s--;
11908 $ if (s > what) s += _tx_snprintf_s (s, size - (s - what), "\n\n");
11909 
11910 $ return (s - what);
11911  }
11912 
11913 //-----------------------------------------------------------------------------------------------------------------
11914 
11915 intptr_t _txDumpExceptionObj (char what[], intptr_t size, void* object, size_t sizeObj, const std::type_info* type) //-V2008
11916  {
11917 $6 assert (what);
11918 $ assert (size > 0); //-V547
11919 
11920 $ static char* s = NULL; s = what;
11921 $ static size_t szObj = 0; szObj = sizeObj;
11922 
11923  #define PRINT_(...) s += _tx_snprintf_s (s, size - (s - what), ##__VA_ARGS__)
11924 
11925 $ PRINT_ ("\n\n" "Объект исключения C++:");
11926 
11927 $ const char* mangledName = (type)? type->name() : NULL;
11928 
11929 $ char* typeName = NULL;
11930 $ int err = 1;
11931 
11932  #if defined (_GCC_VER)
11933 $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err);
11934  #endif
11935 
11936 $ const char* name = (!err && typeName)? typeName : mangledName; //-V560
11937 
11938 $ if (name &&
11939  (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >") == 0 ||
11940  strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >") == 0))
11941  {$ name = "std::string"; }
11942 
11943 $ if (name &&
11944  (strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *") == 0 ||
11945  strcmp (name, "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * __ptr64") == 0 ||
11946  strcmp (name, "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*") == 0))
11947  {$ name = "std::string*"; }
11948 
11949  if (name) {$ PRINT_ (" %s", name); }
11950 
11951  #if defined (_GCC_VER)
11952 $ free (typeName);
11953  #endif
11954 
11955 $ err = 0;
11956 $ if (mangledName)
11957  {
11958  if (_txSetJmp())
11959  {
11960  #define PRINT_VAL_(fmt, typ, ...) \
11961  else if (*type == typeid ( typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \
11962  else if (*type == typeid (const typ )) {$ PRINT_ (" = " #fmt, (* (typ* ) object) __VA_ARGS__); } \
11963  else if (*type == typeid ( typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \
11964  else if (*type == typeid (const typ* )) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \
11965  else if (*type == typeid ( typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); } \
11966  else if (*type == typeid (const typ* const)) {$ PRINT_ (" = " #fmt, (**(typ**) object) __VA_ARGS__); }
11967  #define NO_
11968 
11969  if (false) ;
11970  PRINT_VAL_ ("%s", char*, NO_) PRINT_VAL_ ('%c', unsigned char, NO_) PRINT_VAL_ (%s, bool, ? "true" : "false") //-V206 //-V517
11971  PRINT_VAL_ ( %d, int, NO_) PRINT_VAL_ ( %u, unsigned int, NO_) PRINT_VAL_ (%g, float, NO_) //-V206
11972  PRINT_VAL_ ( %hd, short, NO_) PRINT_VAL_ ( %hu, unsigned short, NO_) PRINT_VAL_ (%g, double, NO_) //-V206
11973  PRINT_VAL_ ( %ld, long, NO_) PRINT_VAL_ ( %lu, unsigned long, NO_) PRINT_VAL_ ('%c', char, NO_) //-V206
11974  PRINT_VAL_ ("%s", std::string, .c_str()) //-V206
11975 
11976  else if (std::exception* e = dynamic_cast <std::exception*> ( (std::exception* ) object))
11977  {
11978 $ PRINT_ (", what(): \"%s\"", e->what());
11979  }
11980  else
11981  {$ err = 1; }
11982  }
11983  else
11984  {$ err = 2; }
11985  }
11986 
11987 $ _txClearJmp();
11988 
11989 $ if (err && object && szObj)
11990  {
11991 $ const unsigned char* buf = (const unsigned char*) object;
11992 
11993 $ if (szObj >= 64) szObj = 64;
11994 
11995 $ PRINT_ (", дамп: [");
11996 $ for (size_t i = 0; i < szObj; i++) PRINT_ ("%c", (isprint (buf[i]) && !iscntrl (buf[i]))? buf[i] : '.' );
11997 
11998 $ PRINT_ ("]");
11999 $ for (size_t i = 0; i < szObj; i++) PRINT_ (" %02X", buf[i]);
12000 
12001 $ err = 0;
12002  }
12003 
12004 $ if (err)
12005  {$ PRINT_ (" = ??"); }
12006 
12007 $ PRINT_ ((object? "%sего адрес 0x%p." : "%sего адрес NULL."), ((typeName || mangledName)? ", " : ""), object); //-V560
12008 
12009  #undef PRINT_VAL_
12010  #undef PRINT_
12011  #undef NO_
12012 
12013 $ return s - what;
12014  }
12015 
12016 #endif // TX_COMPILED
12017 
12018 //}
12019 //-----------------------------------------------------------------------------------------------------------------
12020 
12021 //-----------------------------------------------------------------------------------------------------------------
12022 //{ Stack trace and debug info access
12023 //-----------------------------------------------------------------------------------------------------------------
12024 
12025 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
12026 
12027 const char* _txCaptureStackBackTrace (int framesToSkip /*= 0*/, bool readSource /*= true*/,
12028  CONTEXT* context /*= NULL*/, EXCEPTION_POINTERS* exc /*= NULL*/,
12029  HANDLE thread /*= GetCurrentThread()*/)
12030  {
12031 $6 const int maxFrames = 62; // MS says: < 63
12032 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = "";
12033 
12034  if (framesToSkip == -1) {$ return trace; }
12035 
12036 $ static void* capture [maxFrames] = {};
12037 $ int frames = _txStackWalk (framesToSkip + !context, sizearr (capture), capture, context, thread);
12038 
12039 $ memset (trace, 0, sizeof (trace));
12040 $ char* s = trace;
12041 
12042  #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (trace) - 1 - 3 - (s-trace), ##__VA_ARGS__)
12043 
12044 $ for (int i = 0, n = 0; i < frames; i++) //-V2530
12045  {
12046 $ void* addr = capture[i];
12047 
12048 $ Win32::SYMBOL_INFO* sym = NULL;
12049 $ Win32::IMAGEHLP_LINE64* line = NULL;
12050 $ const char* module = NULL;
12051 $ const char* source = NULL;
12052 $ bool inTX = false;
12053 
12054  if (addr) {$ inTX = _txSymGetFromAddr ((char*) addr - 1, &sym, &line, &module); }
12055  if (readSource && !inTX) {$ _txSymGetFromAddr ((void*) 1, NULL, NULL, NULL, &source, 2); } //-V566
12056 
12057 $ int nl = 0;
12058 $ while (s > trace && s[-1] == '\n') { s--; nl++; }
12059 
12060  #if !defined (_TX_FULL_STACKTRACE)
12061 
12062 $ if (! ((sym && *sym->Name) || (line && ((line->FileName && *line->FileName) || line->LineNumber))))
12063  {$ continue; }
12064 
12065  #endif
12066 
12067 $ PRINT_ ("%s#%2d 0x%p", ((n)? ((source || nl)? "\n\n" : "\n") : ""), i, addr);
12068 $ n++;
12069 
12070  if (addr == 0) {$ PRINT_ (" [Неверный фрейм]"); break; }
12071  if (addr == (void*) -1) {$ PRINT_ (" [Странный фрейм]"); break; }
12072  if (addr == (void*)(uintptr_t) 0xBAADF00D) {$ PRINT_ (" [Мусор от LocalAlloc()]"); break; } //-V566
12073 
12074  if (module) {$ PRINT_ (" in %s%s", module, ((sym && *sym->Name)? ": " : "")); }
12075  if (sym && *sym->Name) {$ PRINT_ ("%s()", sym->Name); }
12076  if (line && line->FileName) {$ PRINT_ (" at %s", line->FileName); }
12077  if (line && line->LineNumber) {$ PRINT_ (" (%d)", (int) line->LineNumber); }
12078  if (source) {$ PRINT_ (":\n\n" "%s\n", source); }
12079 
12080  if (sym && strcmp (sym->Name , "main") == 0) {$ break; }
12081  }
12082 
12083  #if defined (_MSC_VER)
12084  #pragma warning (push)
12085  #pragma warning (disable: 28199) // Using possibly uninitialized memory '*s'
12086  #endif
12087 
12088 $ while (s > trace && s[-1] == '\n') s--;
12089 $ *s = 0;
12090 
12091  #if defined (_MSC_VER)
12092  #pragma warning (pop) // Using possibly uninitialized memory '*s'
12093  #endif
12094 
12095  #undef PRINT_
12096 
12097 $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), "");
12098 
12099  #if !defined (_TX_NO_MINIDUMP)
12100 $ _txCreateMiniDump (exc);
12101  #endif
12102 
12103 $ return trace;
12104  }
12105 
12106 //-----------------------------------------------------------------------------------------------------------------
12107 
12108 // Stack WALKING if the program is DEAD. Dead, Carl!
12109 
12110 int _txStackWalk (int framesToSkip, size_t szCapture, void* capture[], CONTEXT* context /*= NULL*/,
12111  HANDLE thread /* = GetCurrentThread()*/)
12112  {
12113 $6 namespace MinGW = Win32::MinGW;
12114 
12115 $ assert (capture);
12116 
12117 $ HANDLE process = GetCurrentProcess();
12118 $ bool thisThread = !Win32::GetThreadId || (Win32::GetThreadId (thread) == GetCurrentThreadId());
12119 
12120 $ CONTEXT ctx = {};
12121 $ ctx.ContextFlags |= CONTEXT_FULL;
12122 
12123 $ int isWow64 = 0;
12124 $ if (Win32::IsWow64Process) Win32::IsWow64Process (process, &isWow64);
12125  else {$ return -1; }
12126 
12127 $ if (context)
12128  {
12129 $ ctx = *context;
12130  }
12131  else
12132  {
12133 $ if (thisThread)
12134  {
12135 $ _TX_CALLv (Win32::RtlCaptureContext, (&ctx));
12136  }
12137  else
12138  {
12139 $ SuspendThread (thread); //-V720
12140 
12141 $ ctx.ContextFlags = CONTEXT_ALL;
12142 $ bool ok = !!GetThreadContext (thread, &ctx);
12143 
12144 $ if (!ok)
12145  {
12146 $ ResumeThread (thread);
12147 $ return -1;
12148  }
12149  }
12150  }
12151 
12152 $ Win32::STACKFRAME64 frame = {};
12153 $ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = Win32::AddrModeFlat;
12154 
12155 $ int cpu = 0;
12156 
12157  #if defined (_WIN64)
12158 
12159 $ if (isWow64)
12160  {
12161 $ Win32::WOW64_CONTEXT wow64ctx = {};
12162 $ wow64ctx.ContextFlags |= WOW64_CONTEXT_FULL;
12163 
12164 $ if (!_TX_CALL (Win32::Wow64GetThreadContext, (thread, &wow64ctx))) // This call fails in WINE,
12165  { // while EXIT_PROCESS_DEBUG_EVENT
12166  if (!thisThread) {$ ResumeThread (thread); }
12167 $ return 0;
12168  }
12169 
12170 $ cpu = IMAGE_FILE_MACHINE_I386;
12171 
12172 $ frame.AddrPC .Offset = wow64ctx.Eip;
12173 $ frame.AddrStack.Offset = wow64ctx.Esp;
12174 $ frame.AddrFrame.Offset = wow64ctx.Ebp;
12175  }
12176  else
12177  {
12178 $ cpu = IMAGE_FILE_MACHINE_AMD64;
12179 
12180 $ frame.AddrPC .Offset = ctx.Rip;
12181 $ frame.AddrStack.Offset = ctx.Rbp;
12182 $ frame.AddrFrame.Offset = ctx.Rsp;
12183  }
12184 
12185  #else
12186 
12187  {
12188 $ cpu = IMAGE_FILE_MACHINE_I386;
12189 
12190 $ frame.AddrPC .Offset = ctx.Eip;
12191 $ frame.AddrStack.Offset = ctx.Ebp;
12192 $ frame.AddrFrame.Offset = ctx.Esp;
12193  }
12194 
12195  #endif
12196 
12197 $ assert (cpu);
12198 
12199  if (_txSetJmp())
12200  {
12201 $ _txSymGetFromAddr ((void*) 1); //-V566
12202  }
12203 $ _txClearJmp();
12204 
12205 $ int frames = -1;
12206 
12207 $ for (frames = -framesToSkip; frames < (int) szCapture; frames++) //-V202 //-V2530
12208  {
12209 $ DWORD64 prev = frame.AddrStack.Offset;
12210 
12211  // Я злой и страшный серый walk. Я в поросятах знаю talk.
12212 
12213  if (!_txSetJmp()) {$ break; }
12214 
12215 #if defined (_GCC_VER)
12216 
12217  if (!_TX_CALL (MinGW::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL,
12218  MinGW::SymFunctionTableAccess64, MinGW::SymGetModuleBase64, NULL))) {$ break; }
12219 #elif defined (_MSC_VER)
12220 
12221 $ if (!_TX_CALL (Win32::StackWalk64, (cpu, process, thread, &frame, &ctx, NULL,
12222  Win32::SymFunctionTableAccess64, Win32::SymGetModuleBase64, NULL))) {$ break; }
12223 #else
12224  #error _GCC_VER / _MSC_VER not defined
12225 #endif
12226  if (frames < 0) {$ continue; }
12227 
12228 $ void* addr = (void*) frame.AddrPC.Offset;
12229 
12230  if (frame.AddrFrame.Offset == 0) {$ addr = 0; } // Bad frame
12231  if (frame.AddrStack.Offset < prev) {$ addr = (void*) -1; } // Strange frame
12232 
12233 $ assert (0 <= frames && frames < (int) szCapture); //-V202
12234 
12235 $ capture[frames] = addr; //-V108
12236  }
12237 
12238 $ _txClearJmp();
12239 
12240  if (!thisThread) {$ ResumeThread (thread); }
12241 
12242 $ return frames;
12243  }
12244 
12245 // Note that Rick and Carl are speaking near the C language block. "C block", Carl. See: http://knowyourmeme.com/memes/carl
12246 
12247 //-----------------------------------------------------------------------------------------------------------------
12248 
12249 bool _txSymGetFromAddr (void* addr, Win32::SYMBOL_INFO** symbol /*= NULL*/,
12250  Win32::IMAGEHLP_LINE64** line /*= NULL*/, const char** module /*= NULL*/,
12251  const char** source /*= NULL*/, int context /*= 2*/)
12252  {
12253 $7 static HANDLE process = NULL;
12254 
12255 #if defined (_GCC_VER)
12256  #define LIB_ Win32::MinGW
12257 
12258 #elif defined (_MSC_VER)
12259  #define LIB_ Win32
12260 
12261 #else
12262  #error _GCC_VER / _MSC_VER not defined
12263 #endif
12264 
12265 $ if (!process && addr)
12266  {
12267 $ process = GetCurrentProcess();
12268 
12269 $ DWORD options = SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING | SYMOPT_INCLUDE_32BIT_MODULES |
12270  SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS;
12271 
12272 $ _TX_CALL (LIB_::SymSetOptions, (options));
12273 $ _TX_CALL (LIB_::SymInitialize, (process, NULL, true));
12274  }
12275 
12276 $ static DWORD64 mod = 0;
12277 
12278 $ if (module)
12279  {
12280 $ static char sMod [MAX_PATH] = "";
12281 $ memset (sMod, 0, sizeof (sMod));
12282 
12283 $ mod = _TX_CALL (LIB_::SymGetModuleBase64, (process, (uintptr_t) addr));
12284 
12285 $ GetModuleFileName ((HMODULE)(intptr_t) mod, sMod, MAX_PATH);
12286 
12287 $ char* ext = strrchr (sMod, '.');
12288  if (ext) {$ _strlwr_s (ext, sizeof (sMod) - (ext-sMod)); }
12289 
12290 $ *module = sMod;
12291  }
12292 
12293 $ static char buffer [_TX_BUFSIZE] = "";
12294 $ static Win32::SYMBOL_INFO* sym = (Win32::SYMBOL_INFO*) buffer; //-V1032
12295 
12296 $ if (symbol)
12297  {
12298 $ memset (buffer, 0, sizeof (buffer));
12299 
12300 $ sym->MaxNameLen = sizeof (buffer) - sizeof (Win32::SYMBOL_INFO) - 1;
12301 $ sym->SizeOfStruct = sizeof (Win32::SYMBOL_INFO);
12302 $ unsigned long long ofs = 0;
12303 
12304 $ _TX_CALL (LIB_::SymFromAddr, (process, (uintptr_t) addr, &ofs, sym));
12305 
12306  if (strcmp (sym->Name, "??") == 0) {$ *sym->Name = 0; }
12307 
12308 $ *symbol = sym;
12309  }
12310 
12311 $ static Win32::IMAGEHLP_LINE64 line64 = { sizeof (line) };
12312 
12313 $ if (line)
12314  {
12315 $ memset (&line64, 0, sizeof (line64));
12316 
12317 $ DWORD ofs = 0;
12318 $ _TX_CALL (LIB_::SymGetLineFromAddr64, (process, (uintptr_t) addr, &ofs, &line64));
12319 
12320 $ *line = &line64;
12321  }
12322 
12323 $ if (source)
12324  {
12325 $ static char buf [_TX_BUFSIZE] = "";
12326 $ memset (buf, 0, sizeof (buf));
12327 
12328 $ if (line64.FileName && line64.LineNumber)
12329  {
12330 $ _txReadSource (buf, sizeof (buf) - 1, line64.FileName,
12331  (int) line64.LineNumber - context, (int) line64.LineNumber + context, (int) line64.LineNumber);
12332 
12333 $ *source = buf;
12334  }
12335 
12336  if (!*source || !**source) {$ *source = NULL; }
12337  }
12338 
12339 $ if (!addr && process)
12340  {
12341 $ _TX_CALL (LIB_::SymCleanup, (process));
12342 
12343 $ process = NULL;
12344  }
12345 
12346  #if (_GCC_VER == 481)
12347  #pragma GCC diagnostic push
12348  #pragma GCC system_header
12349  #endif
12350 
12351 $ if (symbol)
12352  {
12353 $ if (strstr (sym->Name, "::TX::") ||
12354  (strncmp (sym->Name, "_tx", 3) == 0 && isupper ((unsigned char) sym->Name[3])) ||
12355  (strncmp (sym->Name, "tx", 2) == 0 && isupper ((unsigned char) sym->Name[2])) ||
12356  strncmp (sym->Name, "_tx_", 4) == 0 || //-V112
12357  strncmp (sym->Name, "tx_", 3) == 0)
12358  {
12359 $ return true;
12360  }
12361 
12362  #if (_GCC_VER == 481)
12363  #pragma GCC diagnostic pop
12364  #endif
12365 
12366 $ if (!line || !line64.FileName) return false;
12367 
12368 $ intptr_t len = strlen (line64.FileName) - (sizeof (__FILE__) - 1);
12369 
12370 $ return (len >= 0 && _stricmp (line64.FileName + len, __FILE__) == 0) &&
12371  (len == 0 || line64.FileName[len-1] == '/' || line64.FileName[len-1] == '\\');
12372  }
12373 
12374  #undef LIB_
12375 
12376 $ return false;
12377  }
12378 
12379 //-----------------------------------------------------------------------------------------------------------------
12380 
12381 intptr_t _txReadSource (char buf[], intptr_t size, const char file[],
12382  int linStart /*= 0*/, int linEnd /*= INT_MIN*/, int linMark /*= INT_MIN*/)
12383  {
12384 $7 assert (buf);
12385 
12386  if (!file || !*file) {$ return 0; }
12387 
12388  if (linStart < 1) {$ linStart = 1; }
12389  if (linEnd == -1) {$ linEnd = INT_MAX; }
12390 
12391 $ FILE* f = NULL;
12392 $ fopen_s (&f, file, "r");
12393  if (!f) {$ return 0; }
12394 
12395 $ int n = 1;
12396  while (!feof (f))
12397  {
12398  if (n >= linStart) {$ break; }
12399  while (!feof (f) && fgetc (f) != '\n')
12400  ;
12401  n++;
12402  }
12403 
12404 $ char* s = buf;
12405 
12406  #define SZ_ ( size - 3 - (s - buf) )
12407 
12408 $ while (!feof (f) && SZ_ > 0)
12409  {
12410  if (n > linEnd || _txNOP (SZ_) < 0) {$ break; }
12411 
12412  if (linMark != INT_MIN)
12413  {$ s += _tx_snprintf_s (s, SZ_, "%s%5d: ", ((n == linMark)? "=>" : " "), n); }
12414 
12415 $ int c = 0;
12416 $ while (!feof (f) && SZ_ > 0 && (c = fgetc (f)) != '\n') *s++ = (char) c;
12417  if (c == EOF) {$ s--; }
12418 
12419  if (SZ_ > 0) {$ *s++ = '\n'; }
12420 $ n++;
12421  }
12422 
12423  if (n <= linEnd && SZ_ <= 0)
12424  {$ s += _tx_snprintf_s (s, size - (s - buf), "..."); }
12425 
12426  #undef SZ_
12427 
12428 $ fclose (f);
12429 
12430  if (s > buf && s[-1] == '\n') {$ s--; }
12431 $ *s = 0;
12432 
12433 $ return (s - buf);
12434  }
12435 
12436 //-----------------------------------------------------------------------------------------------------------------
12437 
12438 const char* _txCaptureStackBackTraceTX (int framesToSkip /*= 0*/, bool readSource /*= false*/)
12439  {
12440 $6 const int maxFrames = 62; // TX says too: < 63
12441 $ static char trace [(MAX_PATH + 1024+1) * maxFrames] = "";
12442 
12443  if (framesToSkip == -1) {$ return trace; }
12444 
12445 $ memset (trace, 0, sizeof (trace));
12446 $ char* s = trace;
12447 
12448  #define SZ_ ( sizeof (trace) - 1 - 3 - (s-trace) )
12449 
12450 $ const _txLoc* loc = &_txLoc::Cur;
12451 
12452  for (int i = 0; loc && i < framesToSkip + 1; i++, loc = loc->prev) { $; }
12453 
12454 $ for (int i = -framesToSkip; loc && i < maxFrames; i++, loc = loc->prev)
12455  {
12456  if (i < 0) {$ continue; }
12457 
12458  if (loc->func || loc->file || loc->line)
12459  {
12460 $ s += _tx_snprintf_s (s, SZ_, "%s#%2d in %s at %s:%d", (i? readSource? "\n\n" : "\n" : ""),
12461  i, loc->func, loc->file, loc->line);
12462 
12463 $ if (readSource)
12464  {
12465 $ s += _tx_snprintf_s (s, SZ_, ":\n\n");
12466 $ s += _txReadSource (s, SZ_, loc->file, loc->line - 2, loc->line + 2, loc->line);
12467  }
12468  }
12469  }
12470 
12471  #undef SZ_
12472 
12473 $ s += _tx_snprintf_s (s, sizeof (trace) - 1 - (s-trace), "");
12474 
12475 $ return trace;
12476  }
12477 
12478 //-----------------------------------------------------------------------------------------------------------------
12479 
12480 bool _txCreateMiniDump (EXCEPTION_POINTERS* exc /*= NULL*/)
12481  {
12482 $6 static char dumpName[MAX_PATH] = "";
12483  if (!*dumpName) {$ _tx_snprintf_s (dumpName, sizeof (dumpName) - 1, "%s.dmp", _txLogName); }
12484 
12485 $ HANDLE file = CreateFile (dumpName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
12486 
12487  if (!file || file == INVALID_HANDLE_VALUE) {$ return false; }
12488 
12489 $ Win32::MINIDUMP_EXCEPTION_INFORMATION excInfo = { GetCurrentThreadId(), exc, false };
12490 $ Win32::MINIDUMP_TYPE type = (Win32::MINIDUMP_TYPE) (Win32::MiniDumpWithIndirectlyReferencedMemory | Win32::MiniDumpScanMemory);
12491 
12492 $ bool ok = _TX_CALL (Win32::MiniDumpWriteDump, (GetCurrentProcess(), GetCurrentProcessId(), file, type,
12493  ((exc)? &excInfo : NULL), NULL, NULL));
12494 $ CloseHandle (file);
12495 
12496  if (ok) {$ return true; }
12497  else {$ return false; }
12498  }
12499 
12500 #endif // TX_COMPILED
12501 
12502 //}
12503 //-----------------------------------------------------------------------------------------------------------------
12504 
12505 //-----------------------------------------------------------------------------------------------------------------
12506 //{ Errors reporting
12507 //-----------------------------------------------------------------------------------------------------------------
12508 
12509 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
12510 
12511 const char* _txProcessError (const char file[], int line, const char func[], unsigned color, const char msg[], va_list args) //-V2008
12512  {
12513  _txErrors = _txErrors + 1;
12514 
12515  DWORD winErr = GetLastError();
12516 
12517  int crtErr = errno;
12518 
12519  #if !defined (__CYGWIN__)
12520  unsigned long dosErr = _doserrno;
12521  #else
12522  unsigned long dosErr = 0;
12523  #endif
12524 
12525  unsigned dlgErr = _TX_CALL (Win32::CommDlgExtendedError, ());
12526 
12527  unsigned oglErr = _TX_CALL (Win32::wglGetCurrentDC, ())? _TX_CALL (Win32::glGetError, ()) : _txOGLError;
12528 
12529  unsigned threadId = GetCurrentThreadId();
12530 
12531  enum { isFatal = 0x01, isWarning = 0x02, noMsgBox = 0x04, fmtOnly = 0x08, traceSE = 0x10 };
12532  unsigned options = 0;
12533 
12534  for (; msg && *msg; msg++)
12535  {
12536  if (*msg == '\a') options |= isFatal;
12537  else if (*msg == '\v') options |= isWarning;
12538  else if (*msg == '\b') options |= noMsgBox;
12539  else if (*msg == '\f') options |= fmtOnly;
12540  else if (*msg == '\t') options |= traceSE;
12541  else break;
12542  }
12543 
12544  const char* stkTrace = NULL;
12545  const char* txTrace = NULL; (void) txTrace;
12546 
12547  if (!(options & fmtOnly))
12548  {
12549  stkTrace = ((options & traceSE) && *_txTraceSE)? _txTraceSE : _txCaptureStackBackTrace (2, true);
12550  txTrace = _txCaptureStackBackTraceTX (0, true);
12551  }
12552 
12553  static char what[_TX_BIGBUFSIZE*10] = "";
12554  static char str [_TX_BIGBUFSIZE] = "";
12555  char *s = what;
12556 
12557  #define PRINT_(...) s += _tx_snprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__)
12558  #define VPRINT_(...) s += _tx_vsnprintf_s (s, sizeof (what) - 1 - (s - what), ##__VA_ARGS__)
12559 
12560  PRINT_ ("TXLib %s\n\n", ((options & isWarning)? "предупреждает:" :
12561  (options & isFatal)? "соболезнует..." :
12562  "сообщает:"));
12563  PRINT_ ("Программа: %s", txGetModuleFileName());
12564  if (file) PRINT_ (", файл: %s", file);
12565  if (line) PRINT_ (", строка: %d", line);
12566  if (func) PRINT_ (", функция: %s", func);
12567  PRINT_ (",\n\n");
12568 
12569  if (msg) PRINT_ ("%s: ", (file || line || func)? "Сообщение : "ВНЕЗАПНО"), VPRINT_ (msg, args); while (s > what && s[-1] == '\n') s--; PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s", _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, threadId, (threadId == _txMainThreadId)? " (Main)" : (threadId == _txCanvas_ThreadId)? " (Canvas)" : ""); if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr), s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102 NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202 s -= (s[-1] == '.')? 1 : 0, PRINT_ (")"); if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str)); if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str)); if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr))); if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr); #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L) PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : ""); #else PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : ""); #endif if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) && (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func)) PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func); txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what); if (options & fmtOnly) { SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif return what; } txSetProgress (-1, Win32::TBPF_ERROR); unsigned restore = txGetConsoleAttr(); txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED); if (color) {$ txSetConsoleAttr (color); } int oldCodePage = txSetLocale(); fprintf (stderr, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); if (stkTrace && strstr (stkTrace, ".exe: ")) {$ fprintf (stderr, "Стек вызовов:\n\n" "%s\n\n" "--------------------------------------------------\n", stkTrace); } SetConsoleOutputCP (oldCodePage); txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { FILE* log = NULL; fopen_s (&log, _txLogName, "a"); if (!log) {$ break; } fprintf (log, "\n" "--------------------------------------------------\n" "%s\n" "--------------------------------------------------\n", what); fprintf (log, "Стек вызовов:\n\n" //-V576 "%s\n", (*_txTraceSE)? _txTraceSE : stkTrace); #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG) if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace) { fprintf (log, "\n" "--------------------------------------------------\n" "Стек вызовов TX:\n\n" "%s\n", txTrace); } #endif fprintf (log, "\n" "--------------------------------------------------\n" "%s\n\n" "--------------------------------------------------\n", _txAppInfo()); fclose (log); break; } while (false); txSleep(); int ret = 0; if (!(options & noMsgBox)) { txSleep (_txWindowUpdateInterval); PRINT_ ("\n" "Прервать программу?"); ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" : (options & isFatal)? "Фатальная ошибка" : "Ошибка в программе"), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки : "ВНЕЗАПНО"),
12570  VPRINT_ (msg, args);
12571 
12572  while (s > what && s[-1] == '\n') s--;
12573 
12574  PRINT_ ("\n\n" "#%d: %s, Instance: 0x%p (%d-bit), Flags: %c%c%c%c%c%d, Thread: 0x%X%s",
12575 
12576  _txErrors, _TX_VERSION, (void*) &_txInitialized, (sizeof (void*) == 4)? 32 : 64,
12577 
12578  "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace,
12579 
12580  threadId, (threadId == _txMainThreadId)? " (Main)" :
12581  (threadId == _txCanvas_ThreadId)? " (Canvas)" : "");
12582 
12583  if (winErr) PRINT_ (", GetLastError(): %lu (", (unsigned long) winErr),
12584  s += FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, //-V102
12585  NULL, winErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
12586  s, (DWORD) (sizeof (what) - (s-what)), NULL) - 2, //-V202
12587  s -= (s[-1] == '.')? 1 : 0,
12588  PRINT_ (")");
12589 
12590  if (crtErr) PRINT_ (", errno: %d (%s)", crtErr, (strerror_s (str, sizeof (str), crtErr), str));
12591  if (dosErr) PRINT_ (", _doserrno: %lu (%s)", dosErr, (strerror_s (str, sizeof (str), dosErr), str));
12592  if (oglErr) PRINT_ (", glGetError(): %u (0x%04X, %s)", oglErr, oglErr, _TX_CALL (Win32::gluErrorString, (oglErr)));
12593  if (dlgErr) PRINT_ (", CommDlgExtendedError(): %u (0x%04X)", dlgErr, dlgErr);
12594 
12595  #if (__cplusplus >= 201703L) || (defined (_MSVC_LANG) && _MSVC_LANG >= 201703L)
12596  PRINT_ (". %s\n", ::std::uncaught_exceptions()? "std::uncaught_exceptions(): true." : "");
12597  #else
12598  PRINT_ (". %s\n", ::std::uncaught_exception ()? "std::uncaught_exception(): true." : "");
12599  #endif
12600 
12601  if (_txLoc::Cur.inTX > 0 && file && !(_txLoc::Cur.line == line && _stricmp (_txLoc::Cur.file, file) == 0) &&
12602  (_txLoc::Cur.file || _txLoc::Cur.line || _txLoc::Cur.func))
12603  PRINT_ ("From: %s:%d %s.\n", _txLoc::Cur.file, _txLoc::Cur.line, _txLoc::Cur.func);
12604 
12605  txOutputDebugPrintf ("\r" "%s - ERROR: %s\n", _TX_VERSION, what);
12606 
12607  if (options & fmtOnly)
12608  {
12609  SetLastError (winErr);
12610 
12611  errno = crtErr;
12612 
12613  #if !defined (__CYGWIN__)
12614  _doserrno = dosErr;
12615  #endif
12616 
12617  return what;
12618  }
12619 
12620  txSetProgress (-1, Win32::TBPF_ERROR);
12621 
12622  unsigned restore = txGetConsoleAttr();
12623  txSetConsoleAttr ((options & isFatal)? FOREGROUND_LIGHTMAGENTA : FOREGROUND_LIGHTRED);
12624  if (color) {$ txSetConsoleAttr (color); }
12625 
12626  int oldCodePage = txSetLocale();
12627 
12628  fprintf (stderr, "\n" "--------------------------------------------------\n"
12629  "%s\n"
12630  "--------------------------------------------------\n",
12631  what);
12632 
12633  if (stkTrace && strstr (stkTrace, ".exe: "))
12634  {$ fprintf (stderr, "Стек вызовов:\n\n"
12635  "%s\n\n"
12636  "--------------------------------------------------\n",
12637  stkTrace); }
12638 
12639  SetConsoleOutputCP (oldCodePage);
12640  txSetConsoleAttr (restore);
12641 
12642  if (*_txLogName) do //-V2530
12643  {
12644  FILE* log = NULL; fopen_s (&log, _txLogName, "a");
12645  if (!log) {$ break; }
12646 
12647  fprintf (log, "\n" "--------------------------------------------------\n"
12648  "%s\n"
12649  "--------------------------------------------------\n",
12650  what);
12651 
12652  fprintf (log, "Стек вызовов:\n\n" //-V576
12653  "%s\n",
12654  (*_txTraceSE)? _txTraceSE : stkTrace);
12655 
12656  #if defined (_TX_ALLOW_TRACE) || defined (_DEBUG)
12657 
12658  if (_txLoc::Cur.inTX > 0 && txTrace && *txTrace)
12659  {
12660  fprintf (log, "\n" "--------------------------------------------------\n"
12661  "Стек вызовов TX:\n\n"
12662  "%s\n",
12663  txTrace);
12664  }
12665 
12666  #endif
12667 
12668  fprintf (log, "\n" "--------------------------------------------------\n"
12669  "%s\n\n"
12670  "--------------------------------------------------\n",
12671  _txAppInfo());
12672  fclose (log);
12673  break;
12674  }
12675  while (false);
12676 
12677  txSleep();
12678 
12679  int ret = 0;
12680 
12681  if (!(options & noMsgBox))
12682  {
12684 
12685  PRINT_ ("\n" "Прервать программу?");
12686 
12687  ret = txMessageBox (what, ((options & isWarning)? "Предупреждение" :
12688  (options & isFatal)? "Фатальная ошибка" :
12689  "Ошибка в программе), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL); } SetLastError (winErr); errno = crtErr; #if !defined (__CYGWIN__) _doserrno = dosErr; #endif if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES) { txUnlock(); _txCleanup(); Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE); } #undef PRINT_ #undef VPRINT_ return what; } //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) int _txOnErrorReport (int type, const char* text, int* ret) { assert (text); assert (ret); _txErrors = _txErrors + 1; unsigned restore = txGetConsoleAttr(); switch (type) { case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break; case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break; case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break; default: break; //-V2522 } const char startReport[] = "Detected memory leaks!\n", endReport[] = "Object dump complete.\n"; if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать? { _txOnErrorReport (type, "\n", NULL); _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL); _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL); _txOnErrorReport (type, "\n", NULL); } size_t len = strlen (text); if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text); else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION); else txOutputDebugPrintf ("%s\n", text); DWORD n = 0; HANDLE err = GetStdHandle (STD_ERROR_HANDLE); WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202 txSetConsoleAttr (restore); if (*_txLogName) do //-V2530 { HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log == INVALID_HANDLE_VALUE) break; SetFilePointer (log, 0, NULL, FILE_END); WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202 CloseHandle (log); break; } while (false); if (ret) *ret = 0; return (type == _CRT_WARN); } #endif //----------------------------------------------------------------------------------------------------------------- int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/) { $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]"; $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]"; if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); } if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); } $ txSleep(); $ HWND wnd = _txCanvas_Window; $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()), textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST); $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU); $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU)) { $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0); $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); } $ return ret; } //----------------------------------------------------------------------------------------------------------------- bool txGetAsyncKeyState (int key) { $1 HWND wnd = GetForegroundWindow(); return (GetAsyncKeyState (key) & 0x8000) && (wnd == txWindow() || wnd == Win32::GetConsoleWindow()); } //----------------------------------------------------------------------------------------------------------------- bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...) { $5 if (_TX_ARGUMENT_FAILED (format)) return false; $ va_list arg; va_start (arg, format); $ bool ok = true; #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500) $ NOTIFYICONDATA nid = { sizeof (nid) }; $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO; $ nid.hWnd = NULL; $ nid.uID = 1; $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon); $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip)); $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1); $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg); $ nid.dwInfoFlags = flags; $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo); $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid); $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid); $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted; #else $ char nid_szInfo[_TX_BUFSIZE] = ""; $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg); $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo); $ ok = false; $ (void)flags; (void)title; #endif $ va_end (arg); return ok; } //----------------------------------------------------------------------------------------------------------------- void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...) { unsigned id = GetCurrentThreadId(); const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}}; char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)]; char msgStr[_TX_BUFSIZE] = ""; if (msg) { va_list arg; va_start (arg, msg); _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg); va_end (arg); } txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n", _TX_VERSION, (void*) &_txInitialized, "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit], _txLoc::Cur.trace, mark, (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line, 2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""), ((*msgStr && func)? ": " : ""), msgStr); } //----------------------------------------------------------------------------------------------------------------- int txOutputDebugPrintf (const char* format, ...) { if (!format) return 0; enum { msgbox = 1, print = 2, compr = 4 }; int options = 0; for (; format && *format; format++) { if (*format == '\a') options |= msgbox; else if (*format == '\f') options |= print; else if (*format == '\r') options |= compr; else break; } char text[_TX_BIGBUFSIZE] = ""; va_list arg; va_start (arg, format); int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202 va_end (arg); struct __ { static int trimSpaces (char str[]) { char *dst = str, *src = str; for (char d = ' '; d; src++) if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; } else *dst++ = d = *src; return (int) (dst - str - 1); //-V202 }}; if (options & compr) n = __::trimSpaces (text); OutputDebugString (text); if (options & print) fprintf (stderr, "%s", text); if (options & msgbox) txMessageBox (text, "Оказывается, что", MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки), MB_ICONSTOP | MB_SYSTEMMODAL | MB_YESNOCANCEL);
12690  }
12691 
12692  SetLastError (winErr);
12693 
12694  errno = crtErr;
12695 
12696  #if !defined (__CYGWIN__)
12697  _doserrno = dosErr;
12698  #endif
12699 
12700  if (((options & isFatal) && !IsDebuggerPresent()) || ret == IDYES)
12701  {
12702  txUnlock();
12703  _txCleanup();
12704  Win32::TerminateProcess (GetCurrentProcess(), EXIT_FAILURE);
12705  }
12706 
12707  #undef PRINT_
12708  #undef VPRINT_
12709 
12710  return what;
12711  }
12712 
12713 //-----------------------------------------------------------------------------------------------------------------
12714 
12715 #if defined (_MSC_VER)
12716 
12717 int _txOnErrorReport (int type, const char* text, int* ret)
12718  {
12719  assert (text);
12720  assert (ret);
12721 
12722  _txErrors = _txErrors + 1;
12723 
12724  unsigned restore = txGetConsoleAttr();
12725 
12726  switch (type)
12727  {
12728  case _CRT_WARN: txSetConsoleAttr (FOREGROUND_LIGHTRED); break;
12729  case _CRT_ERROR: txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA); break;
12730  case _CRT_ASSERT: txSetConsoleAttr (FOREGROUND_YELLOW); break;
12731  default: break; //-V2522
12732  }
12733 
12734  const char startReport[] = "Detected memory leaks!\n",
12735  endReport[] = "Object dump complete.\n";
12736 
12737  if (strcmp (text, startReport) == 0) // Dirty, dirty hack. А что делать?
12738  {
12739  _txOnErrorReport (type, "\n", NULL);
12740  _txOnErrorReport (type, _TX_VERSION " - ERROR: ", NULL);
12741  _txOnErrorReport (type, "Внимание: Обнаружены утечки памяти! (Для поиска используйте _TX_ALLOC_BREAK.)\n", NULL);
12742  _txOnErrorReport (type, "\n", NULL);
12743  }
12744 
12745  size_t len = strlen (text);
12746  if (text [len-1] != '\n') txOutputDebugPrintf ("%s", text);
12747  else if (strcmp (text, endReport) != 0) txOutputDebugPrintf ("%s" "%s - ERROR: ", text, _TX_VERSION);
12748  else txOutputDebugPrintf ("%s\n", text);
12749 
12750  DWORD n = 0;
12751  HANDLE err = GetStdHandle (STD_ERROR_HANDLE);
12752  WriteFile (err, text, (DWORD) strlen (text), &n, NULL); //-V202
12753 
12754  txSetConsoleAttr (restore);
12755 
12756  if (*_txLogName) do //-V2530
12757  {
12758  HANDLE log = CreateFile (_txLogName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
12759  if (log == INVALID_HANDLE_VALUE) break;
12760 
12761  SetFilePointer (log, 0, NULL, FILE_END);
12762  WriteFile (log, text, (DWORD) strlen (text), &n, NULL); //-V202
12763 
12764  CloseHandle (log);
12765  break;
12766  }
12767  while (false);
12768 
12769  if (ret) *ret = 0;
12770 
12771  return (type == _CRT_WARN);
12772  }
12773 
12774 #endif
12775 
12776 //-----------------------------------------------------------------------------------------------------------------
12777 
12778 int txMessageBox (const char text[], const char header[], unsigned flags /*= MB_ICONINFORMATION | MB_OKCANCEL*/)
12779  {
12780 $5 static wchar_t textW [_TX_BIGBUFSIZE * sizeof (wchar_t)] = L"[NULL text]";
12781 $ static wchar_t headerW [_TX_BUFSIZE * sizeof (wchar_t)] = L"[NULL header]";
12782 
12783  if (text) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, text, -1, textW, sizearr (textW)) || memset (textW, 0, sizeof (textW)); }
12784  if (header) {$ MultiByteToWideChar (_TX_CODEPAGE, 0, header, -1, headerW, sizearr (headerW)) || memset (headerW, 0, sizeof (headerW)); }
12785 
12786 $ txSleep();
12787 
12788 $ HWND wnd = _txCanvas_Window;
12789 $ int ret = MessageBoxW ((wnd && IsWindowVisible (wnd))? wnd : _TX_CALL (Win32::GetConsoleWindow,()),
12790  textW, headerW, flags | MB_SETFOREGROUND | MB_TOPMOST);
12791 
12792 $ GetAsyncKeyState (VK_SHIFT); GetAsyncKeyState (VK_CONTROL); GetAsyncKeyState (VK_MENU);
12793 
12794 $ if (ret == IDCANCEL && GetAsyncKeyState (VK_SHIFT) && GetAsyncKeyState (VK_CONTROL) && GetAsyncKeyState (VK_MENU))
12795  {
12796 $ SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0);
12797 $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT);
12798  }
12799 
12800 $ return ret;
12801  }
12802 
12803 //-----------------------------------------------------------------------------------------------------------------
12804 
12805 bool txGetAsyncKeyState (int key)
12806  {
12807 $1 HWND wnd = GetForegroundWindow();
12808 
12809  return (GetAsyncKeyState (key) & 0x8000) &&
12810  (wnd == txWindow() || wnd == Win32::GetConsoleWindow());
12811  }
12812 
12813 //-----------------------------------------------------------------------------------------------------------------
12814 
12815 bool txNotifyIcon (unsigned flags, const char* title, const char* format, ...)
12816  {
12817 $5 if (_TX_ARGUMENT_FAILED (format)) return false;
12818 
12819 $ va_list arg; va_start (arg, format);
12820 $ bool ok = true;
12821 
12822  #if defined (_WIN32_IE) && (_WIN32_IE >= 0x0500)
12823 
12824 $ NOTIFYICONDATA nid = { sizeof (nid) };
12825 
12826 $ nid.uFlags = NIF_ICON | NIF_TIP | NIF_INFO;
12827 $ nid.hWnd = NULL;
12828 $ nid.uID = 1;
12829 $ nid.hIcon = _txCreateTXIcon (16); assert (nid.hIcon);
12830 $ strncpy_s (nid.szTip, sizeof (nid.szTip), "TXLib Information", sizeof (nid.szTip));
12831 $ strncpy_s (nid.szInfoTitle, sizeof (nid.szInfoTitle), (title? title : "TXLib сообщает"), sizeof (nid.szInfoTitle) - 1);
12832 $ _tx_vsnprintf_s (nid.szInfo, sizeof (nid.szInfo), format, arg);
12833 $ nid.dwInfoFlags = flags;
12834 
12835 $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification)\n", nid.szInfoTitle, nid.szInfo);
12836 
12837 $ ok &= !!Shell_NotifyIcon (NIM_ADD, (::NOTIFYICONDATA*) &nid);
12838 $ ok &= !!Shell_NotifyIcon (NIM_MODIFY, (::NOTIFYICONDATA*) &nid);
12839 
12840 $ if (nid.hIcon) DestroyIcon (nid.hIcon) asserted;
12841 
12842  #else
12843 
12844 $ char nid_szInfo[_TX_BUFSIZE] = "";
12845 $ _tx_vsnprintf_s (nid_szInfo, sizeof (nid_szInfo), format, arg);
12846 $ txOutputDebugPrintf ("\r" _TX_VERSION " - %s: %s (Icon notification - NOT displayed)\n", title, nid_szInfo);
12847 $ ok = false;
12848 
12849 $ (void)flags; (void)title;
12850 
12851  #endif
12852 
12853 $ va_end (arg);
12854  return ok;
12855  }
12856 
12857 //-----------------------------------------------------------------------------------------------------------------
12858 
12859 void _txTrace (const char* file, int line, const char* func, const char* msg /*= NULL*/, ...)
12860  {
12861  unsigned id = GetCurrentThreadId();
12862 
12863  const char marks[2][2][3] = {{"uU", "cC"}, {"mM", "??"}};
12864 
12865  char mark = marks [id == _txMainThreadId] [id == _txCanvas_ThreadId] [(_txLoc::Cur.inTX > 0)];
12866 
12867  char msgStr[_TX_BUFSIZE] = "";
12868  if (msg)
12869  {
12870  va_list arg; va_start (arg, msg);
12871  _tx_vsnprintf_s (msgStr, sizeof (msgStr) - 1, msg, arg);
12872  va_end (arg);
12873  }
12874 
12875  txOutputDebugPrintf ("%s - 0x%p %c%c%c%c%c%d [%c] - %-*s (%5d) " "|%*s%s" "%s%s\n",
12876 
12877  _TX_VERSION, (void*) &_txInitialized,
12878 
12879  "cC"[!!_txConsole], "mM"[_txMain], "dD"[_txIsDll], "rR"[_txRunning], "eE"[_txExit],
12880  _txLoc::Cur.trace, mark,
12881 
12882  (int) sizeof (__FILE__) - 1, (file? file : "(NULL file)"), line,
12883  2 * (_txLoc::Cur.inTX - 1) * !!func, "", (func? func : ""),
12884 
12885  ((*msgStr && func)? ": " : ""), msgStr);
12886  }
12887 
12888 //-----------------------------------------------------------------------------------------------------------------
12889 
12890 int txOutputDebugPrintf (const char* format, ...)
12891  {
12892  if (!format) return 0;
12893 
12894  enum { msgbox = 1, print = 2, compr = 4 };
12895  int options = 0;
12896 
12897  for (; format && *format; format++)
12898  {
12899  if (*format == '\a') options |= msgbox;
12900  else if (*format == '\f') options |= print;
12901  else if (*format == '\r') options |= compr;
12902  else break;
12903  }
12904 
12905  char text[_TX_BIGBUFSIZE] = "";
12906 
12907  va_list arg; va_start (arg, format);
12908  int n = (int) _tx_vsnprintf_s (text, sizeof (text) - 1-1, format, arg); //-V202
12909  va_end (arg);
12910 
12911  struct __ { static int trimSpaces (char str[])
12912  {
12913  char *dst = str, *src = str;
12914 
12915  for (char d = ' '; d; src++)
12916  if (isspace ((unsigned char)(*src))) { if (d != ' ') *dst++ = d = ' '; }
12917  else *dst++ = d = *src;
12918 
12919  return (int) (dst - str - 1); //-V202
12920  }};
12921 
12922  if (options & compr) n = __::trimSpaces (text);
12923 
12924  OutputDebugString (text);
12925 
12926  if (options & print) fprintf (stderr, "%s", text);
12927 
12928  if (options & msgbox) txMessageBox (text, "Оказывается, что, MB_ICONEXCLAMATION); return n; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...) { if (!format) return 0; va_list arg; va_start (arg, format); intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg); va_end (arg); return ret; } //----------------------------------------------------------------------------------------------------------------- intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg) { if (!stream || !format) return 0; #if defined (_TRUNCATE) intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg); #else intptr_t ret = _vsnprintf (stream, size, format, arg); #endif if (ret < 0 && size >= 4) //-V112 { const char ellipsis[] = "..."; size_t szEllipsis = sizeof (ellipsis) - 1; strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis); } return (ret >= 0)? ret : size; } //----------------------------------------------------------------------------------------------------------------- #if defined (__CYGWIN__) int _getch() { termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr); termios newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, &newattr); int ch = getchar(); tcsetattr (STDIN_FILENO, TCSANOW, &oldattr); return ch; } //----------------------------------------------------------------------------------------------------------------- int _putch (int ch) { termios old = {}; tcgetattr (STDOUT_FILENO, &old); termios cur = old; cur.c_lflag &= ~ICANON; cur.c_lflag |= ECHO; tcsetattr (STDOUT_FILENO, TCSANOW, &cur); putchar (ch); tcsetattr (STDOUT_FILENO, TCSANOW, &old); return ch; } //----------------------------------------------------------------------------------------------------------------- int _kbhit() { termios old = {}; tcgetattr (STDIN_FILENO, &old); termios cur = old; cur.c_lflag &= ~(ICANON | ECHO); cur.c_cc[VMIN] = 1; cur.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur); fd_set fd = {}; FD_SET (STDIN_FILENO, &fd); timeval tv = {}; int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd); tcsetattr (STDIN_FILENO, TCSAFLUSH, &old); return res; } #endif #endif // TX_COMPILED //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Information //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< const char* txGetModuleFileName (bool fileNameOnly /*= true*/) { static char name[MAX_PATH] = ""; if (!*name) { if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0; char* ext = strrchr (name, '.'); if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name)); } assert (*name); if (fileNameOnly) return name; static char fullName[MAX_PATH] = ""; strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1); char* title = strrchr (fullName, '\\'); if (!title) title = fullName; char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName); size_t sz = sizeof (fullName) - (ext - fullName); strncpy_s (ext, sz-1, " - TXLib", sz); return title + 1; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- inline const char* _txAppInfo() { $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104 char timeS[32] = ""; ctime_s (timeS, sizeof (timeS), &timeT); static char text[_TX_BUFSIZE] = ""; char cwd [MAX_PATH] = ""; _tx_snprintf_s (text, sizeof (text) - 1, "Developed with:\n\n" "The Dumb Artist Library (TX Library)\n" _TX_VERSION "\n" _TX_AUTHOR "\n" "See license on: http://txlib.ru\n\n" "TXLib file:" "\t" __FILE__ "\n" "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n" "Started:" "\t" "%.6s %.4s %.8s\n\n" "Run file:" "\t" "%s\n" "Directory:" "\t" "%s", #if defined (_MSC_VER) "MSVC Runtime", #elif defined (__CYGWIN__) "Cygwin Runtime", #elif defined (_GCC_VER) && defined (_WIN64) __mingw_get_crt_info(), #else "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION), #endif (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112 timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized txGetModuleFileName(), _getcwd (cwd, sizeof (cwd) - 1)); return text; } //} //----------------------------------------------------------------------------------------------------------------- //! @} //} //================================================================================================================= //================================================================================================================= //{ TXLib API implementation // Реализация TXLib API //================================================================================================================= inline const char* txVersion() { return _TX_VERSION; } //----------------------------------------------------------------------------------------------------------------- inline unsigned txVersionNumber() { return _TX_VER; //-V2517 } //----------------------------------------------------------------------------------------------------------------- inline HWND txWindow() { $9 return _txCanvas_Window; } //----------------------------------------------------------------------------------------------------------------- inline HDC& txDC() { return _txCanvas_BackBuf[0]; } //----------------------------------------------------------------------------------------------------------------- inline RGBQUAD* txVideoMemory() { return _txCanvas_Pixels; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentX (HDC dc /*= txDC()*/) { return txGetExtent (dc) .x; } //----------------------------------------------------------------------------------------------------------------- inline int txGetExtentY (HDC dc /*= txDC()*/) { return txGetExtent (dc) .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< POINT txGetExtent (HDC dc /*= txDC()*/) { $0 static POINT err = {-1, -1}; if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; }; if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; } $ BITMAP bmap = {}; $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted; $ POINT size = { bmap.bmWidth, bmap.bmHeight }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txDestroyWindow (HWND wnd /*= txWindow()*/) { $1 if (!wnd || !txWindow()) return false; $ if (wnd != txWindow()) { $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd); } $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false; $ if (_txMain) { $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n" "Возвращайтесь через main(), там вам будут рады.\n"); $ Sleep (_TX_TIMEOUT); } $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT); $ return _txCanvas_Window == NULL; } //----------------------------------------------------------------------------------------------------------------- HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color); $ if (!pen) return (HPEN) NULL; $ if (!_txBuffer_Select (pen, dc)) { $ Win32::DeleteObject (pen); $ return (HPEN) NULL; } $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID) {$ return (HPEN) NULL; } $ return pen; } //----------------------------------------------------------------------------------------------------------------- COLORREF txColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514 $ int size = Win32::GetObject (obj, 0, NULL); $ Win32::GetObject (obj, sizeof (buf), &buf) asserted; $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor; } //----------------------------------------------------------------------------------------------------------------- HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color); $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL); } //----------------------------------------------------------------------------------------------------------------- COLORREF txFillColor (double red, double green, double blue) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)); $ return txSetFillColor (color)? color : CLR_INVALID; } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetFillColor (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc); $ assert (obj); if (!obj) return CLR_INVALID; //-V547 $ LOGBRUSH buf = {}; $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted; $ return buf.lbColor; } //----------------------------------------------------------------------------------------------------------------- bool txClear (HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc); $ return true; } //----------------------------------------------------------------------------------------------------------------- bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/) { $1 if (red > 1) red = 1; if (red < 0) red = 0; $ if (green > 1) green = 1; if (green < 0) green = 0; $ if (blue > 1) blue = 1; if (blue < 0) blue = 0; $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc); } //----------------------------------------------------------------------------------------------------------------- COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID; $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc); $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (points)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txCircle (double x, double y, double r) { $1 return txEllipse (x-r, y-r, x+r, y+r); } //----------------------------------------------------------------------------------------------------------------- bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) }; $ double start = startAngle * txPI/180, end = (startAngle + totalAngle) * txPI/180; $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1), ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)), ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc); } //----------------------------------------------------------------------------------------------------------------- bool txFloodFill (double x, double y, COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc); $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc); } //----------------------------------------------------------------------------------------------------------------- bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ int len = (int) strlen (text); //-V202 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDrawText (double x0, double y0, double x1, double y1, const char text[], unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (text)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; #if !defined (NDEBUG) $ if (x0 > x1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1); } $ if (y0 > y1) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1); } #endif $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) }; $ if (!strchr (text, '\n')) format |= DT_SINGLELINE; $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc); $ bool ok = false; $ if (Win32::DrawText) { $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc); $ Win32::GetPixel (dc, 0, 0); $ ok = true; //-V519 } else { $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text); $ ok = false; } $ txSetTextAlign (prev, dc); $ return ok; } //----------------------------------------------------------------------------------------------------------------- HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/, int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/, bool strikeout /*= false*/, double angle /*= 0*/, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL; $ HFONT font = txFontExist (name)? Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3), ROUND (angle*10), 0, bold, italic, underline, strikeout, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, name) : (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT); $ _txBuffer_Select (font, dc); $ return font; } //----------------------------------------------------------------------------------------------------------------- SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/) { $1 SIZE size = {-1, -1}; $ if (_TX_ARGUMENT_FAILED (text)) return size; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size; $ size_t len = strlen (text); $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202 $ return size; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cx; } //----------------------------------------------------------------------------------------------------------------- int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/) { $1 return txGetTextExtent (text, dc) .cy; } //----------------------------------------------------------------------------------------------------------------- unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/) { $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc); } //----------------------------------------------------------------------------------------------------------------- LOGFONT* txFontExist (const char name[]) { $1 if (_TX_ARGUMENT_FAILED (name)) return NULL; $ static LOGFONT font = {}; $ font.lfCharSet = DEFAULT_CHARSET; $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1); $ struct tools { static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data) { $ if (_TX_ARGUMENT_FAILED (fnt)) return 0; $ if (_TX_ARGUMENT_FAILED (data)) return 0; #ifndef __STRICT_ANSI__ $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #else $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE); #endif } }; $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL; } //----------------------------------------------------------------------------------------------------------------- bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (obj)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ return _txBuffer_Select (obj, dc); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/) { $1 POINT size = { ROUND (sizeX), ROUND (sizeY) }; $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels); $ assert (dc); if (!dc) return NULL; //-V547 $ txSetDefaults (dc); $ if (!_txCanvas_UserDCs) return dc; $ txAutoLock _lock; $ _txCanvas_UserDCs->push_back (dc); $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202 $ return dc; } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/) { $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels) { $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels); } //----------------------------------------------------------------------------------------------------------------- HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/, unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/) { $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL; $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL), filename, imageFlags, sizeX, sizeY, loadFlags); $ if (!image) return NULL; $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image); $ if (!(loadFlags & LR_LOADFROMFILE)) return dc; $ static std::map <std::string, unsigned> loadTimes; $ std::string file = filename; $ unsigned time = GetTickCount(); $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT) {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); } $ loadTimes [file] = time; $ return dc; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC* pdc) { $1 if (_TX_ARGUMENT_FAILED (pdc)) return false; $ HDC dc = *pdc; $ bool ok = _txBuffer_Delete (pdc); $ if (!ok) return false; $ if (!_txCanvas_UserDCs) return ok; $ txAutoLock _lock; $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it) if (*it == dc) { $ std::swap (*it, _txCanvas_UserDCs->back()); $ _txCanvas_UserDCs->pop_back(); $ break; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txDeleteDC (HDC dc) { $1 return txDeleteDC (&dc); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage); } //----------------------------------------------------------------------------------------------------------------- bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource); } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/) { // Это проверки того, правильные ли HDC вы передали в функцию. // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а. // При первом чтении это можно пропустить. $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent(). // При первом чтении это можно пропустить. $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest). // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки). // При первом чтении это можно пропустить. #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ bool ok = true; $ if (Win32::TransparentBlt) { // А вот теперь уже надо начать читать. // // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function" // и почитайте про ее параметры. // // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки, MB_ICONEXCLAMATION);
12929 
12930  return n;
12931  }
12932 
12933 //-----------------------------------------------------------------------------------------------------------------
12934 
12935 intptr_t _tx_snprintf_s (char* stream, intptr_t size, const char* format, ...)
12936  {
12937  if (!format) return 0;
12938 
12939  va_list arg; va_start (arg, format);
12940  intptr_t ret = _tx_vsnprintf_s (stream, size, format, arg);
12941  va_end (arg);
12942 
12943  return ret;
12944  }
12945 
12946 //-----------------------------------------------------------------------------------------------------------------
12947 
12948 intptr_t _tx_vsnprintf_s (char stream[], intptr_t size, const char format[], va_list arg)
12949  {
12950  if (!stream || !format) return 0;
12951 
12952  #if defined (_TRUNCATE)
12953  intptr_t ret = _vsnprintf_s (stream, size, _TRUNCATE, format, arg);
12954  #else
12955  intptr_t ret = _vsnprintf (stream, size, format, arg);
12956  #endif
12957 
12958  if (ret < 0 && size >= 4) //-V112
12959  {
12960  const char ellipsis[] = "...";
12961  size_t szEllipsis = sizeof (ellipsis) - 1;
12962 
12963  strncpy_s (stream + size - szEllipsis, szEllipsis+1, ellipsis, szEllipsis);
12964  }
12965 
12966  return (ret >= 0)? ret : size;
12967  }
12968 
12969 //-----------------------------------------------------------------------------------------------------------------
12970 
12971 #if defined (__CYGWIN__)
12972 
12973 int _getch()
12974  {
12975  termios oldattr = {}; tcgetattr (STDIN_FILENO, &oldattr);
12976 
12977  termios newattr = oldattr;
12978  newattr.c_lflag &= ~(ICANON | ECHO);
12979  tcsetattr (STDIN_FILENO, TCSANOW, &newattr);
12980 
12981  int ch = getchar();
12982 
12983  tcsetattr (STDIN_FILENO, TCSANOW, &oldattr);
12984 
12985  return ch;
12986  }
12987 
12988 //-----------------------------------------------------------------------------------------------------------------
12989 
12990 int _putch (int ch)
12991  {
12992  termios old = {}; tcgetattr (STDOUT_FILENO, &old);
12993 
12994  termios cur = old;
12995  cur.c_lflag &= ~ICANON;
12996  cur.c_lflag |= ECHO;
12997  tcsetattr (STDOUT_FILENO, TCSANOW, &cur);
12998 
12999  putchar (ch);
13000 
13001  tcsetattr (STDOUT_FILENO, TCSANOW, &old);
13002 
13003  return ch;
13004  }
13005 
13006 //-----------------------------------------------------------------------------------------------------------------
13007 
13008 int _kbhit()
13009  {
13010  termios old = {}; tcgetattr (STDIN_FILENO, &old);
13011 
13012  termios cur = old;
13013  cur.c_lflag &= ~(ICANON | ECHO);
13014  cur.c_cc[VMIN] = 1;
13015  cur.c_cc[VTIME] = 0;
13016 
13017  tcsetattr (STDIN_FILENO, TCSAFLUSH, &cur);
13018 
13019  fd_set fd = {}; FD_SET (STDIN_FILENO, &fd);
13020  timeval tv = {};
13021 
13022  int res = select (STDIN_FILENO + 1, &fd, NULL, NULL, &tv) && FD_ISSET (STDIN_FILENO, &fd);
13023 
13024  tcsetattr (STDIN_FILENO, TCSAFLUSH, &old);
13025 
13026  return res;
13027  }
13028 
13029 #endif
13030 
13031 #endif // TX_COMPILED
13032 
13033 //}
13034 //-----------------------------------------------------------------------------------------------------------------
13035 
13036 //-----------------------------------------------------------------------------------------------------------------
13037 //{ Information
13038 //-----------------------------------------------------------------------------------------------------------------
13039 
13040 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
13041 
13042 const char* txGetModuleFileName (bool fileNameOnly /*= true*/)
13043  {
13044  static char name[MAX_PATH] = "";
13045 
13046  if (!*name)
13047  {
13048  if (!GetModuleFileName (NULL, name, sizeof (name) - 1)) *name = 0;
13049 
13050  char* ext = strrchr (name, '.');
13051  if (ext) _strlwr_s (ext, sizeof (name) - 1 - (ext - name));
13052  }
13053 
13054  assert (*name);
13055 
13056  if (fileNameOnly) return name;
13057 
13058  static char fullName[MAX_PATH] = "";
13059  strncpy_s (fullName, sizeof (fullName), name, sizeof (fullName) - 1);
13060 
13061  char* title = strrchr (fullName, '\\'); if (!title) title = fullName;
13062  char* ext = strrchr (fullName, '.'); if (!ext) ext = fullName + strlen (fullName);
13063 
13064  size_t sz = sizeof (fullName) - (ext - fullName);
13065  strncpy_s (ext, sz-1, " - TXLib", sz);
13066 
13067  return title + 1;
13068  }
13069 
13070 #endif // TX_COMPILED
13071 
13072 //-----------------------------------------------------------------------------------------------------------------
13073 
13074 inline const char* _txAppInfo()
13075  {
13076 $1 time_t timeT = time (NULL) - clock()/CLOCKS_PER_SEC; //-V104
13077  char timeS[32] = "";
13078  ctime_s (timeS, sizeof (timeS), &timeT);
13079 
13080  static char text[_TX_BUFSIZE] = "";
13081  char cwd [MAX_PATH] = "";
13082 
13083  _tx_snprintf_s (text, sizeof (text) - 1,
13084 
13085  "Developed with:\n\n"
13086  "The Dumb Artist Library (TX Library)\n"
13087  _TX_VERSION "\n" _TX_AUTHOR "\n"
13088  "See license on: http://txlib.ru\n\n"
13089 
13090  "TXLib file:" "\t" __FILE__ "\n"
13091  "Compiled:" "\t" __DATE__ " " __TIME__ ", " __TX_COMPILER__ ", %s, %d-bit, " _TX_BUILDMODE "\n"
13092  "Started:" "\t" "%.6s %.4s %.8s\n\n"
13093 
13094  "Run file:" "\t" "%s\n"
13095  "Directory:" "\t" "%s",
13096 
13097  #if defined (_MSC_VER)
13098  "MSVC Runtime",
13099  #elif defined (__CYGWIN__)
13100  "Cygwin Runtime",
13101  #elif defined (_GCC_VER) && defined (_WIN64)
13102  __mingw_get_crt_info(),
13103  #else
13104  "MinGW Runtime " TX_QUOTE (__MINGW32_MAJOR_VERSION) "." TX_QUOTE (__MINGW32_MINOR_VERSION),
13105  #endif
13106  (sizeof (void*) == sizeof (DWORD))? 32 : 64, //-V112
13107 
13108  timeS + 4, timeS + 20, timeS + 11, //-V112 These offsets are ANSI standardized
13110  _getcwd (cwd, sizeof (cwd) - 1));
13111 
13112  return text;
13113  }
13114 
13115 //}
13116 //-----------------------------------------------------------------------------------------------------------------
13117 
13119 //}
13120 //=================================================================================================================
13121 
13122 //=================================================================================================================
13123 //{ TXLib API implementation
13124 // Реализация TXLib API
13125 //=================================================================================================================
13126 
13127 inline const char* txVersion()
13128  {
13129  return _TX_VERSION;
13130  }
13131 
13132 //-----------------------------------------------------------------------------------------------------------------
13133 
13134 inline unsigned txVersionNumber()
13135  {
13136  return _TX_VER; //-V2517
13137  }
13138 
13139 //-----------------------------------------------------------------------------------------------------------------
13140 
13141 inline HWND txWindow()
13142  {
13143 $9 return _txCanvas_Window;
13144  }
13145 
13146 //-----------------------------------------------------------------------------------------------------------------
13147 
13148 inline HDC& txDC()
13149  {
13150  return _txCanvas_BackBuf[0];
13151  }
13152 
13153 //-----------------------------------------------------------------------------------------------------------------
13154 
13155 inline RGBQUAD* txVideoMemory()
13156  {
13157  return _txCanvas_Pixels;
13158  }
13159 
13160 //-----------------------------------------------------------------------------------------------------------------
13161 
13162 inline int txGetExtentX (HDC dc /*= txDC()*/)
13163  {
13164  return txGetExtent (dc) .x;
13165  }
13166 
13167 //-----------------------------------------------------------------------------------------------------------------
13168 
13169 inline int txGetExtentY (HDC dc /*= txDC()*/)
13170  {
13171  return txGetExtent (dc) .y;
13172  }
13173 
13174 //-----------------------------------------------------------------------------------------------------------------
13175 
13176 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
13177 
13178 POINT txGetExtent (HDC dc /*= txDC()*/)
13179  {
13180 $0 static POINT err = {-1, -1};
13181 
13182  if (!dc) {$ POINT screen = { GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN) }; return screen; };
13183 
13184  if (_TX_DEFAULT_HDC_FAILED (dc)) {$ return err; }
13185 
13186 $ BITMAP bmap = {};
13187 $ txGDI (Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap), dc) asserted;
13188 
13189 $ POINT size = { bmap.bmWidth, bmap.bmHeight };
13190 $ return size;
13191  }
13192 
13193 //-----------------------------------------------------------------------------------------------------------------
13194 
13195 bool txDestroyWindow (HWND wnd /*= txWindow()*/)
13196  {
13197 $1 if (!wnd || !txWindow()) return false;
13198 
13199 $ if (wnd != txWindow())
13200  {
13201 $ return !!SendNotifyMessage (txWindow(), _TX_WM_DESTROYWND, 0, (LPARAM) wnd);
13202  }
13203 
13204 $ if (SendNotifyMessage (txWindow(), (_txMain? WM_CLOSE : WM_DESTROY), 0, 0) == 0) return false;
13205 
13206 $ if (_txMain)
13207  {
13208 $ txNotifyIcon (NIIF_WARNING, NULL, "\n" "Очень, очень плохо завершать программу через txDestroyWindow().\n\n"
13209  "Возвращайтесь через main(), там вам будут рады.\n");
13210 $ Sleep (_TX_TIMEOUT);
13211  }
13212 
13213 $ _txWaitFor (!_txCanvas_Window, _TX_TIMEOUT);
13214 
13215 $ return _txCanvas_Window == NULL;
13216  }
13217 
13218 //-----------------------------------------------------------------------------------------------------------------
13219 
13220 HPEN txSetColor (COLORREF color, double thickness /*= 1*/, HDC dc /*= txDC()*/)
13221  {
13222 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL;
13223 
13224 $ HPEN pen = Win32::CreatePen ((color == TX_TRANSPARENT? PS_NULL : PS_SOLID), ROUND (thickness), color);
13225 
13226 $ if (!pen) return (HPEN) NULL;
13227 
13228 $ if (!_txBuffer_Select (pen, dc))
13229  {
13230 $ Win32::DeleteObject (pen);
13231 $ return (HPEN) NULL;
13232  }
13233 
13234 $ if (txGDI (Win32::SetTextColor (dc, color), dc) == CLR_INVALID)
13235  {$ return (HPEN) NULL; }
13236 
13237 $ return pen;
13238  }
13239 
13240 //-----------------------------------------------------------------------------------------------------------------
13241 
13242 COLORREF txColor (double red, double green, double blue)
13243  {
13244 $1 if (red > 1) red = 1; if (red < 0) red = 0;
13245 $ if (green > 1) green = 1; if (green < 0) green = 0;
13246 $ if (blue > 1) blue = 1; if (blue < 0) blue = 0;
13247 
13248 $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255));
13249 
13250 $ return txSetColor (color)? color : CLR_INVALID;
13251  }
13252 
13253 //-----------------------------------------------------------------------------------------------------------------
13254 
13255 COLORREF txGetColor (HDC dc /*= txDC()*/)
13256  {
13257 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID;
13258 
13259 $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_PEN)), dc);
13260 $ assert (obj); if (!obj) return CLR_INVALID; //-V547
13261 
13262 $ union { EXTLOGPEN extLogPen; LOGPEN LogPen; } buf = {}; //-V2514
13263 
13264 $ int size = Win32::GetObject (obj, 0, NULL);
13265 $ Win32::GetObject (obj, sizeof (buf), &buf) asserted;
13266 
13267 $ return (size == sizeof (LOGPEN))? buf.LogPen.lopnColor : buf.extLogPen.elpColor;
13268  }
13269 
13270 //-----------------------------------------------------------------------------------------------------------------
13271 
13272 HBRUSH txSetFillColor (COLORREF color, HDC dc /*= txDC()*/)
13273  {
13274 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL;
13275 
13276 $ HBRUSH brush = (color == TX_TRANSPARENT)? (HBRUSH) Win32::GetStockObject (HOLLOW_BRUSH) : Win32::CreateSolidBrush (color);
13277 
13278 $ return (_txBuffer_Select (brush, dc))? brush : (Win32::DeleteObject (brush), (HBRUSH) NULL);
13279  }
13280 
13281 //-----------------------------------------------------------------------------------------------------------------
13282 
13283 COLORREF txFillColor (double red, double green, double blue)
13284  {
13285 $1 if (red > 1) red = 1; if (red < 0) red = 0;
13286 $ if (green > 1) green = 1; if (green < 0) green = 0;
13287 $ if (blue > 1) blue = 1; if (blue < 0) blue = 0;
13288 
13289 $ COLORREF color = RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255));
13290 
13291 $ return txSetFillColor (color)? color : CLR_INVALID;
13292  }
13293 
13294 //-----------------------------------------------------------------------------------------------------------------
13295 
13296 COLORREF txGetFillColor (HDC dc /*= txDC()*/)
13297  {
13298 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID;
13299 
13300 $ HGDIOBJ obj = txGDI ((Win32::GetCurrentObject (dc, OBJ_BRUSH)), dc);
13301 $ assert (obj); if (!obj) return CLR_INVALID; //-V547
13302 
13303 $ LOGBRUSH buf = {};
13304 $ txGDI ((Win32::GetObject (obj, sizeof (buf), &buf)), dc) asserted;
13305 
13306 $ return buf.lbColor;
13307  }
13308 
13309 //-----------------------------------------------------------------------------------------------------------------
13310 
13311 bool txClear (HDC dc /*= txDC()*/)
13312  {
13313 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13314 
13315 $ POINT size = txGetExtent (dc);
13316 $ return txGDI (!!(Win32::PatBlt (dc, 0, 0, size.x, size.y, PATCOPY)), dc);
13317  }
13318 
13319 //-----------------------------------------------------------------------------------------------------------------
13320 
13321 bool txSetPixel (double x, double y, COLORREF color, HDC dc /*= txDC()*/)
13322  {
13323 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13324 
13325 $ txGDI ((Win32::SetPixel (dc, ROUND (x), ROUND (y), color)), dc);
13326 
13327 $ return true;
13328  }
13329 
13330 //-----------------------------------------------------------------------------------------------------------------
13331 
13332 bool txPixel (double x, double y, double red, double green, double blue, HDC dc /*= txDC()*/)
13333  {
13334 $1 if (red > 1) red = 1; if (red < 0) red = 0;
13335 $ if (green > 1) green = 1; if (green < 0) green = 0;
13336 $ if (blue > 1) blue = 1; if (blue < 0) blue = 0;
13337 
13338 $ return txSetPixel (x, y, RGB (ROUND (red * 255), ROUND (green * 255), ROUND (blue * 255)), dc);
13339  }
13340 
13341 //-----------------------------------------------------------------------------------------------------------------
13342 
13343 COLORREF txGetPixel (double x, double y, HDC dc /*= txDC()*/)
13344  {
13345 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return CLR_INVALID;
13346 
13347 $ return txGDI ((Win32::GetPixel (dc, ROUND (x), ROUND (y))), dc);
13348  }
13349 
13350 //-----------------------------------------------------------------------------------------------------------------
13351 
13352 bool txLine (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/)
13353  {
13354 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13355 
13356 $ bool ok = txGDI ((Win32::MoveToEx (dc, ROUND (x0), ROUND (y0), NULL)), dc);
13357 $ ok &= txGDI ((Win32::LineTo (dc, ROUND (x1), ROUND (y1) )), dc);
13358 
13359 $ return ok;
13360  }
13361 
13362 //-----------------------------------------------------------------------------------------------------------------
13363 
13364 bool txRectangle (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/)
13365  {
13366 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13367 
13368 $ return txGDI ((Win32::Rectangle (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc);
13369  }
13370 
13371 //-----------------------------------------------------------------------------------------------------------------
13372 
13373 bool txPolygon (const POINT points[], int numPoints, HDC dc /*= txDC()*/)
13374  {
13375 $1 if (_TX_ARGUMENT_FAILED (points)) return false;
13376 $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13377 
13378 $ return txGDI (!!(Win32::Polygon (dc, points, numPoints)), dc);
13379  }
13380 
13381 //-----------------------------------------------------------------------------------------------------------------
13382 
13383 bool txEllipse (double x0, double y0, double x1, double y1, HDC dc /*= txDC()*/)
13384  {
13385 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13386 
13387 $ return txGDI ((Win32::Ellipse (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1))), dc);
13388  }
13389 
13390 //-----------------------------------------------------------------------------------------------------------------
13391 
13392 bool txCircle (double x, double y, double r)
13393  {
13394 $1 return txEllipse (x-r, y-r, x+r, y+r);
13395  }
13396 
13397 //-----------------------------------------------------------------------------------------------------------------
13398 
13399 bool txArc (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/)
13400  {
13401 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13402 
13403 $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) };
13404 
13405 $ double start = startAngle * txPI/180,
13406  end = (startAngle + totalAngle) * txPI/180;
13407 
13408 $ return txGDI (!!(Win32::Arc (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1),
13409  ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)),
13410  ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc);
13411  }
13412 
13413 //-----------------------------------------------------------------------------------------------------------------
13414 
13415 bool txPie (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/)
13416  {
13417 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13418 
13419 $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) };
13420 
13421 $ double start = startAngle * txPI/180,
13422  end = (startAngle + totalAngle) * txPI/180;
13423 
13424 $ return txGDI (!!(Win32::Pie (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1),
13425  ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)),
13426  ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc);
13427  }
13428 
13429 //-----------------------------------------------------------------------------------------------------------------
13430 
13431 bool txChord (double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc /*= txDC()*/)
13432  {
13433 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13434 
13435 $ POINT center = { ROUND ((x0 + x1) /2), ROUND ((y0 + y1) /2) };
13436 
13437 $ double start = startAngle * txPI/180,
13438  end = (startAngle + totalAngle) * txPI/180;
13439 
13440 $ return txGDI (!!(Win32::Chord (dc, ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1),
13441  ROUND (center.x + 1E3*cos (start)), ROUND (center.y - 1E3*sin (start)),
13442  ROUND (center.x + 1E3*cos (end)), ROUND (center.y - 1E3*sin (end)))), dc);
13443  }
13444 
13445 //-----------------------------------------------------------------------------------------------------------------
13446 
13447 bool txFloodFill (double x, double y,
13448  COLORREF color /*= TX_TRANSPARENT*/, DWORD mode /*= FLOODFILLSURFACE*/, HDC dc /*= txDC()*/)
13449  {
13450 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13451 
13452 $ if (color == TX_TRANSPARENT) color = txGetPixel (x, y, dc);
13453 
13454 $ return txGDI (!!(Win32::ExtFloodFill (dc, ROUND (x), ROUND (y), color, mode)), dc);
13455  }
13456 
13457 //-----------------------------------------------------------------------------------------------------------------
13458 
13459 bool txTextOut (double x, double y, const char text[], HDC dc /*= txDC()*/)
13460  {
13461 $1 if (_TX_ARGUMENT_FAILED (text)) return false;
13462 $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13463 
13464 $ int len = (int) strlen (text); //-V202
13465 $ bool ok = txGDI (!!(Win32::TextOut (dc, ROUND (x), ROUND (y), text, len)), dc);
13466 
13467 $ return ok;
13468  }
13469 
13470 //-----------------------------------------------------------------------------------------------------------------
13471 
13472 bool txDrawText (double x0, double y0, double x1, double y1, const char text[],
13473  unsigned format /*= DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS*/,
13474  HDC dc /*= txDC()*/)
13475  {
13476 $1 if (_TX_ARGUMENT_FAILED (text)) return false;
13477 $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13478 
13479 #if !defined (NDEBUG)
13480 
13481 $ if (x0 > x1)
13482  {
13483 $ SetLastError (ERROR_INVALID_DATA);
13484 $ TX_ERROR ("Параметр x0 = %g больше, чем x1 = %g. Текст выводиться не будет.", x0, x1);
13485  }
13486 
13487 $ if (y0 > y1)
13488  {
13489 $ SetLastError (ERROR_INVALID_DATA);
13490 $ TX_ERROR ("Параметр y0 = %g больше, чем y1 = %g. Текст выводиться не будет.", y0, y1);
13491  }
13492 
13493 #endif
13494 
13495 $ RECT r = { ROUND (x0), ROUND (y0), ROUND (x1), ROUND (y1) };
13496 
13497 $ if (!strchr (text, '\n')) format |= DT_SINGLELINE;
13498 
13499 $ unsigned prev = txSetTextAlign (TA_LEFT | TA_TOP | TA_NOUPDATECP, dc);
13500 
13501 $ bool ok = false;
13502 
13503 $ if (Win32::DrawText)
13504  {
13505 $ ok = !!txGDI ((Win32::DrawText (dc, text, -1, &r, format)), dc);
13506 $ Win32::GetPixel (dc, 0, 0);
13507 $ ok = true; //-V519
13508  }
13509  else
13510  {
13511 $ txTextOut ((x0 + x1) / 2, (y0 + y1) / 2, text);
13512 $ ok = false;
13513  }
13514 
13515 $ txSetTextAlign (prev, dc);
13516 
13517 $ return ok;
13518  }
13519 
13520 //-----------------------------------------------------------------------------------------------------------------
13521 
13522 HFONT txSelectFont (const char name[], double sizeY, double sizeX /*= -1*/,
13523  int bold /*= FW_DONTCARE*/, bool italic /*= false*/, bool underline /*= false*/,
13524  bool strikeout /*= false*/, double angle /*= 0*/,
13525  HDC dc /*= txDC()*/)
13526  {
13527 $1 if (_TX_ARGUMENT_FAILED (name)) return NULL;
13528 $ if (_TX_DEFAULT_HDC_FAILED (dc)) return NULL;
13529 
13530 $ HFONT font = txFontExist (name)?
13531  Win32::CreateFont (ROUND (sizeY), ROUND ((sizeX >= 0)? sizeX : sizeY/3),
13532  ROUND (angle*10), 0, bold, italic, underline, strikeout,
13533  RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
13534  DEFAULT_QUALITY, DEFAULT_PITCH, name)
13535  :
13536  (HFONT) Win32::GetStockObject (SYSTEM_FIXED_FONT);
13537 
13538 $ _txBuffer_Select (font, dc);
13539 
13540 $ return font;
13541  }
13542 
13543 //-----------------------------------------------------------------------------------------------------------------
13544 
13545 SIZE txGetTextExtent (const char text[], HDC dc /*= txDC()*/)
13546  {
13547 $1 SIZE size = {-1, -1};
13548 
13549 $ if (_TX_ARGUMENT_FAILED (text)) return size;
13550 $ if (_TX_DEFAULT_HDC_FAILED (dc)) return size;
13551 
13552 $ size_t len = strlen (text);
13553 $ txGDI ((Win32::GetTextExtentPoint32 (dc, text, (int) len, &size)), dc) asserted; //-V202
13554 
13555 $ return size;
13556  }
13557 
13558 //-----------------------------------------------------------------------------------------------------------------
13559 
13560 int txGetTextExtentX (const char text[], HDC dc /*= txDC()*/)
13561  {
13562 $1 return txGetTextExtent (text, dc) .cx;
13563  }
13564 
13565 //-----------------------------------------------------------------------------------------------------------------
13566 
13567 int txGetTextExtentY (const char text[], HDC dc /*= txDC()*/)
13568  {
13569 $1 return txGetTextExtent (text, dc) .cy;
13570  }
13571 
13572 //-----------------------------------------------------------------------------------------------------------------
13573 
13574 unsigned txSetTextAlign (unsigned align /*= TA_CENTER | TA_BASELINE*/, HDC dc /*= txDC()*/)
13575  {
13576 $1 if (_TX_DEFAULT_HDC_FAILED (dc)) return false; //-V601
13577 
13578 $ return txGDI ((Win32::SetTextAlign (dc, align)), dc);
13579  }
13580 
13581 //-----------------------------------------------------------------------------------------------------------------
13582 
13583 LOGFONT* txFontExist (const char name[])
13584  {
13585 $1 if (_TX_ARGUMENT_FAILED (name)) return NULL;
13586 
13587 $ static LOGFONT font = {};
13588 $ font.lfCharSet = DEFAULT_CHARSET;
13589 $ strncpy_s (font.lfFaceName, sizeof (font.lfFaceName), name, sizeof (font.lfFaceName) - 1);
13590 
13591 $ struct tools
13592  {
13593  static int CALLBACK enumFonts (const LOGFONT* fnt, const TEXTMETRIC*, DWORD, LPARAM data)
13594  {
13595 $ if (_TX_ARGUMENT_FAILED (fnt)) return 0;
13596 $ if (_TX_ARGUMENT_FAILED (data)) return 0;
13597 
13598  #ifndef __STRICT_ANSI__
13599 $ return _strnicmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE);
13600 
13601  #else
13602 $ return strncmp (fnt->lfFaceName, ((LOGFONT*)data)->lfFaceName, LF_FACESIZE);
13603 
13604  #endif
13605  }
13606  };
13607 
13608 $ return txGDI ((Win32::EnumFontFamiliesEx (NULL, &font, tools::enumFonts, (LPARAM) &font, 0)), NULL) == 0? &font : NULL;
13609  }
13610 
13611 //-----------------------------------------------------------------------------------------------------------------
13612 
13613 bool txSelectObject (HGDIOBJ obj, HDC dc /*= txDC()*/)
13614  {
13615 $1 if (_TX_ARGUMENT_FAILED (obj)) return false;
13616 $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13617 
13618 $ return _txBuffer_Select (obj, dc);
13619  }
13620 
13621 //-----------------------------------------------------------------------------------------------------------------
13622 
13623 HDC txCreateCompatibleDC (double sizeX, double sizeY, HBITMAP bitmap /*= NULL*/, RGBQUAD** pixels /*= NULL*/)
13624  {
13625 $1 POINT size = { ROUND (sizeX), ROUND (sizeY) };
13626 
13627 $ HDC dc = _txBuffer_Create (NULL, &size, bitmap, pixels);
13628 $ assert (dc); if (!dc) return NULL; //-V547
13629 
13630 $ txSetDefaults (dc);
13631 
13632 $ if (!_txCanvas_UserDCs) return dc;
13633 
13634 $ txAutoLock _lock;
13635 $ _txCanvas_UserDCs->push_back (dc);
13636 
13637 $ if (_txCanvas_UserDCs->size() >= _TX_BUFSIZE)
13638  {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загрузили уже %d HDC, системе может стать плохо.", (int) _txCanvas_UserDCs->size()); } //-V202
13639 
13640 $ return dc;
13641  }
13642 
13643 //-----------------------------------------------------------------------------------------------------------------
13644 
13645 HDC txCreateDIBSection (double sizeX, double sizeY, RGBQUAD** pixels /*= NULL*/)
13646  {
13647 $1 return txCreateCompatibleDC (sizeX, sizeY, NULL, pixels);
13648  }
13649 
13650 //-----------------------------------------------------------------------------------------------------------------
13651 
13652 HDC txCreateDIBSection (double sizeX, double sizeY, COLORREF** pixels)
13653  {
13654 $1 return txCreateDIBSection (sizeX, sizeY, (RGBQUAD**) pixels);
13655  }
13656 
13657 //-----------------------------------------------------------------------------------------------------------------
13658 
13659 HDC txLoadImage (const char filename[], int sizeX /*= 0*/, int sizeY /*= 0*/,
13660  unsigned imageFlags /*= IMAGE_BITMAP*/, unsigned loadFlags /*= LR_LOADFROMFILE*/)
13661  {
13662 $1 if (_TX_ARGUMENT_FAILED (filename && *filename)) return NULL;
13663 
13664 $ HBITMAP image = (HBITMAP) Win32::LoadImage ((loadFlags & LR_LOADFROMFILE)? NULL : GetModuleHandle (NULL),
13665  filename, imageFlags, sizeX, sizeY, loadFlags);
13666 $ if (!image) return NULL;
13667 
13668 $ HDC dc = txCreateCompatibleDC (sizeX, sizeY, image);
13669 
13670 $ if (!(loadFlags & LR_LOADFROMFILE)) return dc;
13671 
13672 $ static std::map <std::string, unsigned> loadTimes;
13673 $ std::string file = filename;
13674 $ unsigned time = GetTickCount();
13675 
13676 $ if ((long) (time - loadTimes [file]) < _TX_TIMEOUT)
13677  {$ txNotifyIcon (NIIF_WARNING, NULL, "Вы загружаете \"%s\" слишком часто, программа будет тормозить.", filename); }
13678 
13679 $ loadTimes [file] = time;
13680 
13681 $ return dc;
13682  }
13683 
13684 //-----------------------------------------------------------------------------------------------------------------
13685 
13686 bool txDeleteDC (HDC* pdc)
13687  {
13688 $1 if (_TX_ARGUMENT_FAILED (pdc)) return false;
13689 
13690 $ HDC dc = *pdc;
13691 $ bool ok = _txBuffer_Delete (pdc);
13692 $ if (!ok) return false;
13693 
13694 $ if (!_txCanvas_UserDCs) return ok;
13695 
13696 $ txAutoLock _lock;
13697 
13698 $ for (std::vector <HDC> ::iterator it = _txCanvas_UserDCs->begin(); it != _txCanvas_UserDCs->end(); ++it)
13699  if (*it == dc)
13700  {
13701 $ std::swap (*it, _txCanvas_UserDCs->back());
13702 $ _txCanvas_UserDCs->pop_back();
13703 $ break;
13704  }
13705 
13706 $ return ok;
13707  }
13708 
13709 //-----------------------------------------------------------------------------------------------------------------
13710 
13711 bool txDeleteDC (HDC dc)
13712  {
13713 $1 return txDeleteDC (&dc);
13714  }
13715 
13716 //-----------------------------------------------------------------------------------------------------------------
13717 
13718 bool txBitBlt (HDC destImage, double xDest, double yDest, double width, double height,
13719  HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, unsigned operation /*= SRCCOPY*/)
13720  {
13721 $1 if (_TX_HDC_FAILED (destImage)) return false;
13722 $ if (_TX_HDC_FAILED (sourceImage)) return false;
13723 
13724 $ POINT size = txGetExtent (sourceImage);
13725 $ if (!width) width = size.x; //-V550
13726 $ if (!height) height = size.y; //-V550
13727 
13728 $ return txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height),
13729  sourceImage, ROUND (xSource), ROUND (ySource), operation)), destImage);
13730  }
13731 
13732 //-----------------------------------------------------------------------------------------------------------------
13733 
13734 bool txBitBlt (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/)
13735  {
13736 $1 if (_TX_TXWINDOW_FAILED()) return false;
13737 
13738 $ return txBitBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource);
13739  }
13740 
13741 //-----------------------------------------------------------------------------------------------------------------
13742 
13743 bool txTransparentBlt (HDC destImage, double xDest, double yDest, double width, double height,
13744  HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, COLORREF transColor /*= TX_BLACK*/)
13745  {
13746  // Это проверки того, правильные ли HDC вы передали в функцию.
13747  // Не бойтесь долларов - <s>это не запрещенная валюта</s> это макросы для отладки TXLib'а.
13748  // При первом чтении это можно пропустить.
13749 
13750 $1 if (_TX_HDC_FAILED (destImage)) return false;
13751 $ if (_TX_HDC_FAILED (sourceImage)) return false;
13752 
13753  // Это автоматическое определение размеров картинки (точнее, HDC источника - source) с помощью txGetExtent().
13754  // При первом чтении это можно пропустить.
13755 
13756 $ POINT size = txGetExtent (sourceImage);
13757 $ if (!width) width = size.x; //-V550
13758 $ if (!height) height = size.y; //-V550
13759 
13760  // Это проверка того, что картинка (или ее часть) правильно попадает в окно (точнее, HDC приемника - destination, dest).
13761  // Если она "вылезает" из окна в любую сторону, то Win32::TransparentBlt() не будет работать. Эта проверка происходит только
13762  // в режиме отладки (когда не задан макрос NDEBUG - No Debugging, без отладки).
13763  // При первом чтении это можно пропустить.
13764 
13765 #if !defined (NDEBUG)
13766 
13767 $ if (!(0 <= xSource && xSource + width <= size.x &&
13768  0 <= ySource && ySource + height <= size.y))
13769  {
13770 $ SetLastError (ERROR_INVALID_DATA);
13771 $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, "
13772  "функция txTransparentBlt() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y);
13773  }
13774 
13775 #endif
13776 
13777 $ bool ok = true;
13778 
13779 $ if (Win32::TransparentBlt)
13780  {
13781  // А вот теперь уже надо начать читать.
13782  //
13783  // Ниже - это вызов стандартной Win32::TransparentBlt() из ядра Windows. Погуглите "Windows TransparentBlt function"
13784  // и почитайте про ее параметры.
13785  //
13786  // Как видите, оригинальная функция из Win32 принимает размеры не только исходной, но и итоговой картинки, и если они не
13787  // совпадают, то картинка будет уменьшена или увеличена. TXlib'овская <s>паленая</s> функция TransparentBlt предполагает, что // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s> // это сделано для упрощения вызова функции TransparentBlt(). // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<-- // // <<-- // ||||| |||||| // <<-- // vvvvv vvvvvv // <<-- // <<-- $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<< sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<< destImage); // <<-- // ^^^^^ ^^^^^^ // <<-- // ||||| |||||| // <<-- // // <<-- } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<-- else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); } // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
13788  // эти размеры всегда совпадают, и поэтому при работе с TransparentBlt() масштаб будет всегда 1:1. <s>Так себе решение, но</s>
13789  // это сделано для упрощения вызова функции TransparentBlt().
13790 
13791  // Только то, что эти параметры передаются одинаковыми, не дает возможность менять масштаб картинки! // <<--
13792  // // <<--
13793  // ||||| |||||| // <<--
13794  // vvvvv vvvvvv // <<--
13795  // <<--
13796 $ ok &= txGDI (!!(Win32::TransparentBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), // <<<<
13797  sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), transColor)), // <<<<
13798  destImage); // <<--
13799  // ^^^^^ ^^^^^^ // <<--
13800  // ||||| |||||| // <<--
13801  // // <<--
13802  } // См. "TransparentBlt function" в Google, ищите смысл параметров wSrc и wDest (hSrc и hDest). Думайте! // <<--
13803  else
13804  {
13805 $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height),
13806  sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)),
13807  destImage);
13808  }
13809 
13810  // В TXLib-овской функции txTransparentBlt() проверок и комментариев больше, чем рабочего кода, и это как бы намекает, что // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s> // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL // или DirectX, будет круто. Хотя это и сложнее.</s> // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами, // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :(( $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txTransparentBlt (double xDest, double yDest, HDC sourceImage, COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor); } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_HDC_FAILED (destImage)) return false; $ if (_TX_HDC_FAILED (sourceImage)) return false; $ POINT size = txGetExtent (sourceImage); $ if (!width) width = size.x; //-V550 $ if (!height) height = size.y; //-V550 #if !defined (NDEBUG) $ if (!(0 <= xSource && xSource + width <= size.x && 0 <= ySource && ySource + height <= size.y)) { $ SetLastError (ERROR_INVALID_DATA); $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, " "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y); } #endif $ if (alpha < 0) alpha = 0; $ if (alpha > 1) alpha = 1; $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 }; $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap); $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551 $ if (Win32::AlphaBlend) { $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)), destImage); } else { $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height), sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)), destImage); $ ok = false; //-V519 } $ return ok; } //----------------------------------------------------------------------------------------------------------------- bool txAlphaBlend (double xDest, double yDest, HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/) { $1 if (_TX_TXWINDOW_FAILED()) return false; $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha); } //----------------------------------------------------------------------------------------------------------------- HDC txUseAlpha (HDC image) { $1 if (_TX_HDC_FAILED (image)) return NULL; $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP); $ if (!bitmap) return NULL; $ DIBSECTION dib = {}; $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted; $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }}; $ RGBQUAD* buf = NULL; $ bool isDIB = (dib.dsBm.bmPlanes == 1 && dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 && dib.dsBmih.biCompression == DIB_RGB_COLORS && dib.dsBm.bmBits); $ if (!isDIB) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ if (!buf) return NULL; $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; } else { $ buf = (RGBQUAD*) dib.dsBm.bmBits; } $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) { RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108 color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0); color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0); color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0); } $ if (!isDIB) { $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted; $ delete[] buf; } $ return image; } //----------------------------------------------------------------------------------------------------------------- bool txSaveImage (const char filename[], HDC dc /*= txDC()*/) { $1 if (_TX_ARGUMENT_FAILED (filename)) return false; $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false; $ POINT size = txGetExtent (dc); $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119 szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104 $ BITMAP bmap = {}; $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }; $ RGBQUAD* buf = NULL; $ bool ok = true; $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap); if (!ok) {$ return false; } $ if (!bmap.bmBits) { $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121 $ ok &= (buf != NULL); $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y, buf, (BITMAPINFO*) &info, DIB_RGB_COLORS); if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); } $ ok &= !!res; } else { $ buf = (RGBQUAD*) bmap.bmBits; } $ FILE* f = NULL; $ if (ok) fopen_s (&f, filename, "wb"); $ ok &= (f != NULL); $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1); $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575 $ ok &= (f && fclose (f) == 0); $ if (!bmap.bmBits) { $ delete[] buf; $ buf = NULL; } $ return ok; } //----------------------------------------------------------------------------------------------------------------- double txSleep (double time) { $1 LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ int lock = _txCanvas_RefreshLock; $ _txCanvas_RefreshLock = 0; $ HWND wnd = txWindow(); if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); } $ Sleep (ROUND ((time >= 0)? time : 0)); $ _txCanvas_RefreshLock = lock; $ LARGE_INTEGER stop = {}; $ QueryPerformanceCounter (&stop) asserted; $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart; } //----------------------------------------------------------------------------------------------------------------- bool txLock (bool wait /*= true*/) { $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048 else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); } } //----------------------------------------------------------------------------------------------------------------- bool txUnlock() { $0 LeaveCriticalSection (&_txCanvas_LockBackBuf); $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0); $ return false; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T txUnlock (T value) { $1 txUnlock(); $ return value; } //----------------------------------------------------------------------------------------------------------------- inline void txRedrawWindow() { $1 txSleep (0); } //----------------------------------------------------------------------------------------------------------------- inline int txUpdateWindow (int update /*= true*/) { $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update); } //----------------------------------------------------------------------------------------------------------------- inline int txBegin() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline int txEnd() { $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1); $ return _txCanvas_RefreshLock; } //----------------------------------------------------------------------------------------------------------------- inline POINT txMousePos() { $1 POINT pos = {}; $ GetCursorPos (&pos); $ if (txWindow()) {$ ScreenToClient (txWindow(), &pos); } $ return pos; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseX() { return (double) txMousePos() .x; } //----------------------------------------------------------------------------------------------------------------- inline double txMouseY() { return (double) txMousePos() .y; } //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< unsigned txMouseButtons() { $1 HWND txWnd = txWindow(); $ HWND foreground = GetForegroundWindow(); $ if ((txWnd && (foreground == txWnd)) || (!txWnd && (foreground == Win32::GetConsoleWindow()))) { $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0 ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1 ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2 } else {$ return 0; } } //----------------------------------------------------------------------------------------------------------------- unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/) { unsigned oldAttr = txGetConsoleAttr(); SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color); SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color); return oldAttr; } //----------------------------------------------------------------------------------------------------------------- unsigned txGetConsoleAttr() { CONSOLE_SCREEN_BUFFER_INFO con = {}; con.wAttributes = FOREGROUND_LIGHTGRAY; GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) || GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con); return con.wAttributes; } //----------------------------------------------------------------------------------------------------------------- POINT txSetConsoleCursorPos (double x, double y) { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left), (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) }; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted; $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return prev; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleCursorPos() { $1 POINT fontSz = txGetConsoleFontSize(); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x), ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) }; $ return pos; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleExtent() { $1 CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted; $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1, con.srWindow.Bottom - con.srWindow.Top + 1 }; $ return size; } //----------------------------------------------------------------------------------------------------------------- bool txClearConsole() { $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); $ CONSOLE_SCREEN_BUFFER_INFO con = {}; $ GetConsoleScreenBufferInfo (out, &con) asserted; $ COORD start = {con.srWindow.Left, con.srWindow.Top}; $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) * (con.srWindow.Bottom - con.srWindow.Top + 1); $ DWORD written = 0; $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted; $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted; $ return written == len; } //----------------------------------------------------------------------------------------------------------------- POINT txGetConsoleFontSize() { $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}}; $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font)); $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y }; if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501 if (size.cx == 0) {$ size.cx = 1; } if (size.cy == 0) {$ size.cy = 1; } $ POINT sizeFont = { size.cx, size.cy }; $ return sizeFont; } //----------------------------------------------------------------------------------------------------------------- bool txTextCursor (bool blink /*= true*/) { $1 bool old = _txConsole_IsBlinking; $ _txConsole_IsBlinking = blink; $ return old; } //----------------------------------------------------------------------------------------------------------------- bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/) { $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT; $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC; $ if (!filename) mode = SND_PURGE; $ return !!Win32::PlaySound (filename, NULL, mode); } //----------------------------------------------------------------------------------------------------------------- int txSpeak (const char* text, ...) { $1 bool verbose = false; (void) verbose; $ bool async = false; (void) async; $ for (; text && *text; text++) { if (*text == '\a') {$ async = true; } else if (*text == '\v') {$ verbose = true; } else break; } $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!"; $ va_list arg; va_start (arg, text); if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); } $ va_end (arg); if (text && verbose) {$ printf ("%s", textA); } #ifdef TX_USE_SPEAK $ int time = GetTickCount(); $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L""; $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW)); $ static ISpVoice* voice = NULL; $ if (text && !voice) { $ HRESULT res = Win32::CoInitialize (NULL); if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); } } $ if (text && voice) { $ Win32::_fpreset(); $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL); $ tx_fpreset(); } $ if (!text && voice) { $ voice->Release(); $ voice = NULL; $ Win32::CoUninitialize(); } $ return (voice)? GetTickCount() - time : -1; #else $ if (text) { $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK); $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA); $ txSetConsoleAttr (oldAttr); } $ return -1; #endif } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[], double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/) { $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1; $ int time = GetTickCount(); //-V2551 $ static char processUID [64] = ""; if (!*processUID) { $ FILETIME startTime = {}, null = {}; $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted; $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo", (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted; } $ if (!fileName) { $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern $ return 0; } $ static const char* vlcPath = _txPlayVideo_FindVLC(); $ if (!vlcPath || _access (vlcPath, 0) != 0) { $ static int once = false; //-V601 $ if (*fileName && !once++) {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org " "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n" "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n" "P.S. См. мое описание в TXLib Help."); } $ return INT_MIN; //-V109 } $ bool async = false; if (*fileName == '\a') {$ async = true; fileName++; } $ RECT rect = {}; if (wnd) {$ GetClientRect (wnd, &rect); } if (!width) {$ width = rect.right; } if (!height) {$ height = rect.bottom; } // Create a child window to hold the video stream $ const char* errPos = "ВНЕЗАПНО"; $ volatile HWND child = NULL; $ if (wnd && (wnd == txWindow())) { $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1); $ static int number = 1; $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass }; $ child = txCreateExtraWindow (createData); $ if (!child) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos)); $ return INT_MIN+3; //-V109 } $ BringWindowToTop (child); $ wnd = child; } // Build the command line if (!zoom && !wnd) {$ zoom = 1; } $ char sZoom [64] = "--autoscale"; if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550 $ static char cmd [MAX_PATH*2 + 1024] = ""; $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit" " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s" " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging" " --ignore-config --reset-config --no-one-instance --play-and-exit" " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file" " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events", vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted; $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n", x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd); $ if (!*fileName) { if (child) {$ txDestroyWindow (child); } $ return (intptr_t) cmd; } $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0) { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos)); if (child) {$ txDestroyWindow (child); } $ return INT_MIN+1; //-V109 } // Run VLC, run $ PROCESS_INFORMATION vlc = {}; $ STARTUPINFO start = { sizeof (start) }; $ DWORD ret = 0; $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) && vlc.hProcess && vlc.hThread) { $ if (child) { $ assert (wnd == child); //-V547 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107 } $ if (!async) { $ WaitForSingleObject (vlc.hProcess, INFINITE); $ GetExitCodeProcess (vlc.hProcess, &ret) asserted; } $ if (!child) { $ CloseHandle (vlc.hProcess) asserted; } $ CloseHandle (vlc.hThread) asserted; $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105 } else { $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s", strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos)); $ if (child) {$ txDestroyWindow (child); } $ return INT_MIN+4; //-V112 //-V109 } #undef PROCESS_UID_ } //----------------------------------------------------------------------------------------------------------------- intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/) { $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd); } //----------------------------------------------------------------------------------------------------------------- LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar) { const UINT_PTR checkTimer = 1; switch (msg) { case WM_CREATE: { $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted; } break; case WM_DESTROY: { $1 KillTimer (wnd, checkTimer) asserted; $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); $ if (vlc) { $ Win32::TerminateProcess (vlc, 0); $ CloseHandle (vlc) asserted; $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0); } } break; case WM_TIMER: { HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA); if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT) { $1 DestroyWindow (wnd) asserted; } } break; default: //-V2522 break; } return DefWindowProc (wnd, msg, wpar, lpar); } //----------------------------------------------------------------------------------------------------------------- const char* _txPlayVideo_FindVLC() { $1 static char vlcPath [MAX_PATH] = ""; $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL)) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath))) { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath))) { $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX); if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106 { if (_access (vlcPath, 0) == 0) {$ return vlcPath; } } $ return NULL; } //----------------------------------------------------------------------------------------------------------------- HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/) { $1 static double oldPercent = 100; if (percent < 0) {$ percent = MIN (oldPercent, 100); } else {$ oldPercent = percent; } $ HRESULT res = S_FALSE; #if defined (__ITaskbarList3_INTERFACE_DEFINED__) $ HRESULT init = Win32::CoInitialize (NULL); $ bool ok = true; $ res = S_OK; $ ITaskbarList3* taskbar = NULL; if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); } $ ok &= !!taskbar && (res == S_OK); if (!wnd) {$ wnd = txWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); } if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); } if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); } if (taskbar) {$ taskbar->Release(); } if (init == S_OK) {$ Win32::CoUninitialize(); } #endif (void) type; (void) wnd; $ return res; } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- // +--<<< Это не те символы, что вы ищете :) // V Полезно смотреть не только вверх, но и вниз inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/) { $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc; $ return old; } //----------------------------------------------------------------------------------------------------------------- // +--<<< А это, наконец, искомое определение этой функции. // | Смотрите по сторонам! Нужная вам функция где-то рядом. // | // v inline bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture() { txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n" "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n" "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. " "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n" "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом " "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n" "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы " "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n", "Не получилось", MB_ICONSTOP); // The truth is out there... (C++files) return false; } //----------------------------------------------------------------------------------------------------------------- // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you. inline bool txDisableAutoPause() { _txExit = true; return true; } // P.S. This library contains more undocumented functions. Search them via "Luke" keyword. //----------------------------------------------------------------------------------------------------------------- #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/) { $1 assert (!_txIsBadReadPtr (address)); $ const unsigned char* addr = (const unsigned char*) address; $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO $ const int _o_u16text = 0x00020000; // and _O_U16TEXT $ bool istty = _txIsTTY (1); $ int mode = _O_TEXT; $ int oldMode = _setmode (stdout_fileno, mode); $ unsigned oldCP = GetConsoleOutputCP(); $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581 $ unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_WHITE); $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : "")); $ txSetConsoleAttr (FOREGROUND_YELLOW); $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x); $ for (unsigned x = 0; x < 16; x++) printf ("%X", x); $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */, L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */, L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */, L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */, L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */, L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */, L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */, L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */, L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */, L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */, L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */, L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */, L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */, L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */, L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */, L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */, L"\x20" /* 32 - Space */}; $ for (int y = 0; y < 16; y++, addr += 16) { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 (void)_setmode (stdout_fileno, mode = oldMode); txSetConsoleAttr (FOREGROUND_YELLOW); printf ("\n" "%*p ", (int) sizeof (address) * 2, addr); int color = FOREGROUND_LIGHTGREEN; for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 printf ("%02X ", addr[x]); } for (unsigned x = 0; x < 16; x++) { txSetConsoleAttr (color + x/4%2); //-V112 unsigned char ch = addr[x]; if (ch >= sizearr (xlat) || !istty) { if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581 if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode); printf ("%c", !strchr ("\t\r\n", ch)? ch : ' '); } else { if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581 if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text); wprintf (L"%lls", xlat[ch]); } } } $ (void)_setmode (stdout_fileno, oldMode); $ printf ("\n"); $ if (pause && istty) { $ txSetConsoleAttr (FOREGROUND_DARKGRAY); $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP); } $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY); $ printf ("\n"); $ txSetConsoleAttr (attr); $ SetConsoleOutputCP (oldCP); } //----------------------------------------------------------------------------------------------------------------- void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/, bool readSource /*= true*/) { $1 unsigned attr = txGetConsoleAttr(); $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN); $ fprintf (stderr, "\n" "--------------------------------------------------\n" "Трассировка стека из \"%s\" at %s:%d:\n\n" "%s\n\n" "--------------------------------------------------\n\n", func, file, line, _txCaptureStackBackTrace (1, readSource)); $ txSetConsoleAttr (attr); } //----------------------------------------------------------------------------------------------------------------- char* txDemangle (const char* mangledName, std::nomeow_t) { $1 if (!mangledName) return NULL; $ char* typeName = NULL; #if defined (_GCC_VER) $ int err = 1; $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err; if (typeName) {$ return typeName; } #endif $ unsigned short flags = 0; $ if (mangledName[0] == '.') { $ mangledName++; $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY } $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags)); if (typeName) {$ return typeName; } $ return _strdup (mangledName); } //----------------------------------------------------------------------------------------------------------------- std::string txDemangle (const char* mangledName) { $1 char* typeName = txDemangle (mangledName, std::nomeow); $ std::string name (typeName? typeName : ""); $ free (typeName); $ return name; } //----------------------------------------------------------------------------------------------------------------- double txQueryPerformance() { $1 int maxTime = 500; $ int maxSamples = 100; $ POINT size = {100, 100}; $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL); $ assert (dc); if (!dc) return -1; //-V547 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202 $ assert (mask); $ LARGE_INTEGER freq = {}; $ QueryPerformanceFrequency (&freq) asserted; $ LARGE_INTEGER start = {}; $ QueryPerformanceCounter (&start) asserted; $ int samples = 0; $ while (samples++ < maxSamples) { $ LARGE_INTEGER cur = {}; $ QueryPerformanceCounter (&cur) asserted; $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart; $ if (t > maxTime) break; // Draw test scene $ for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc); $ for (int y = 0; y < size.y; y += 10) for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc); $ txEllipse (0, 0, size.x, size.y, dc); $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc); $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted; $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted; $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted; } $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202 $ assert (mask); $ _txBuffer_Delete (&dc); $ return 3.0 * samples / sqrt (1.0 * size.x * size.y); } //----------------------------------------------------------------------------------------------------------------- unsigned txExtractColor (COLORREF color, COLORREF component) { $1 switch (component) { case TX_RED: case TX_HUE: $ return (color >> 0) & 0xFF; case TX_GREEN: case TX_SATURATION: $ return (color >> 8) & 0xFF; case TX_BLUE: case TX_LIGHTNESS: $ return (color >> 16) & 0xFF; default: $ return CLR_INVALID; } } //----------------------------------------------------------------------------------------------------------------- COLORREF txRGB2HSL (COLORREF rgbColor) { $1 struct xRGB { static bool zero (double val) { const double prec = 0.001; return (fabs (val) < prec); } }; $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551 g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551 b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551 m1 = MAX (MAX (r, g), b), m2 = MIN (MIN (r, g), b), dm = m1 - m2, sm = m1 + m2, h = 0, s = 0, l = sm / 2; $ if (!xRGB::zero (dm)) { $ sm = (sm <= 1)? sm : (2-sm); $ s = (!xRGB::zero (sm))? dm/sm : 0; $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0, cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0, cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0; $ if (xRGB::zero (r - m1)) h = cb - cg; $ if (xRGB::zero (g - m1)) h = 2 + cr - cb; $ if (xRGB::zero (b - m1)) h = 4 + cg - cr; } $ h = (h >= 0)? h*60 : h*60 + 360; $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255)); } //----------------------------------------------------------------------------------------------------------------- COLORREF txHSL2RGB (COLORREF hslColor) { $1 struct xRGB { static double calc (double h, double m1, double m2) { $2 while (h < 0) h += 360; $ while (h > 360) h -= 360; $ return (h < 60)? m1 + (m2-m1) * h / 60 : (h < 180)? m2 : (h < 240)? m1 + (m2-m1) * (240-h) / 60 : m1; } }; $ int si = txExtractColor (hslColor, TX_SATURATION); $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360, s = txExtractColor (hslColor, TX_SATURATION) / 255.0, l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0, m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s, m1 = 2 * l - m2, r = (si)? xRGB::calc (h + 120, m1, m2) : l, g = (si)? xRGB::calc (h, m1, m2) : l, b = (si)? xRGB::calc (h - 120, m1, m2) : l; $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255)); } //----------------------------------------------------------------------------------------------------------------- void tx_fpreset() { $1 txAutoLock _lock; $ Win32::_fpreset(); $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW #if !defined (__CYGWIN__) $ unsigned old87 = 0; $ if (_controlfp_s (&old87, 0, 0) == 0) {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM #else $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM #endif } #endif // TX_COMPILED //----------------------------------------------------------------------------------------------------------------- #if defined (_TX_CPP11) template <int txFramesToAverage> #endif double txGetFPS (int minFrames) { $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0); $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time); $ if (time.QuadPart - time0.QuadPart == 0) {$ return 0; } $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq); $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart); $ time0 = time; $ if (txFramesToAverage == 0) return fps; $ static _tx_thread double average [txFramesToAverage] = {}; $ static _tx_thread unsigned n = 0; $ average [n++ % txFramesToAverage] = fps; $ unsigned nn = MIN (n, (unsigned) sizearr (average)); $ fps = 0; $ for (unsigned i = 0; i < nn; i++) fps += average[i]; $ fps /= nn; $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline T zero() { T __zero = {}; return __zero; } //----------------------------------------------------------------------------------------------------------------- inline double random (std::nomeow_t, double left, double right) { return left + (right - left) * ((double) rand() / RAND_MAX); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (std::nomeow_t, Tx x, Ta a, Tb b) { return a <= x && x <= b; } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.x, rect.left, rect.right) && In (std::nomeow, pt.y, rect.top, rect.bottom); } //----------------------------------------------------------------------------------------------------------------- inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect) { if (_TX_ARGUMENT_FAILED (&pt)) return false; if (_TX_ARGUMENT_FAILED (&rect)) return false; return In (std::nomeow, pt.X, rect.Left, rect.Right) && In (std::nomeow, pt.Y, rect.Top, rect.Bottom); } //----------------------------------------------------------------------------------------------------------------- inline int random (int range) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return rand() % range; } //----------------------------------------------------------------------------------------------------------------- inline double random (double left, double right) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return random (std::nomeow, left, right); } //----------------------------------------------------------------------------------------------------------------- template <typename Tx, typename Ta, typename Tb> inline bool In (Tx x, Ta a, Tb b) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, x, a, b); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const POINT& pt, const RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //----------------------------------------------------------------------------------------------------------------- inline bool In (const COORD& pt, const SMALL_RECT& rect) { if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206 return In (std::nomeow, pt, rect); } //} //================================================================================================================= //================================================================================================================= //{ txPrintf() implementation // Реализация txPrintf() //================================================================================================================= #if defined (_TX_CPP11) template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args); template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args); void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt); template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg); void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt); //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006 else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args) { $1 assert (&stream); $ assert (fmt); $ _txPrintV (stream, format, n, fmt); if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028 else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); } $ _txPrintV (stream, format, n, fmt, arg); $ _txPrintF (stream, format, n+1, fmt, args...); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt) { $1 assert (fmt); $ _txPrintV (stream, format, n, fmt); if (!fmt[0]) {$} else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); } } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt) { $1 assert (&stream); $ assert (fmt); $ while (*fmt) { if (fmt[0] == '%') { if (fmt[1] == '%') fmt++; else break; } stream << *fmt++; } $ } //----------------------------------------------------------------------------------------------------------------- template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg) { $1 assert (&stream); $ assert (fmt); $ if (_TX_ARGUMENT_FAILED (&arg)) return; if (fmt[0] == '%') {$} else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); } $ fmt++; $ char oldFill = stream.fill (' '); $ std::ios_base::fmtflags oldFlags = stream.flags(); $ for (;;) switch (*fmt) { case '-': $ stream << std::left; fmt++; break; case '+': $ stream << std::showpos; fmt++; break; case ' ': $ stream.fill (' '); fmt++; break; case '#': $ stream << std::showbase; fmt++; break; case '0': $ stream.fill ('0'); fmt++; break; default: $ goto end; } end: $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0); $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0; if (width) {$ stream << std::setw (width); } if (prec) {$ stream << std::setprecision (prec); } $ fmt += strspn (fmt, "hljztL"); $ switch (*fmt) { case '$': case '?': $ break; case 'd': case 'i': case 'u': $ stream << std::dec; break; case 'o': $ stream << std::oct; break; case 'x': $ stream << std::hex; break; case 'X': $ stream << std::hex << std::uppercase; break; case 'f': $ stream << std::fixed; break; case 'F': $ stream << std::fixed << std::uppercase; break; case 'e': $ stream << std::scientific; break; case 'E': $ stream << std::scientific << std::uppercase; break; case 'g': $ break; case 'G': $ stream << std::uppercase; break; case 'a': $ break; case 'A': $ stream << std::uppercase; break; case 'c': case 's': case 'p': $ break; default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break; } $ fmt++; if (&arg) {$ stream << arg; } else {$ stream << "(null)"; } $ stream.fill (oldFill); $ stream.flags (oldFlags); } //----------------------------------------------------------------------------------------------------------------- inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009 { $1 assert (fmt); if (_TX_ARGUMENT_FAILED (arg)) return; if (fmt[0] == '%' && fmt[1] == 'n') {$} else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); } $ *arg = (int) stream.str().length(); //-V202 $ fmt += 2; } //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; } inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ const char* fmt = format; $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0; $ if (_TX_ARGUMENT_FAILED (&format)) return 0; $ if (size > 0) size--; $ buffer[size] = 0; $ if (!size) return 0; $ std::ostringstream stream; $ stream.rdbuf() -> pubsetbuf (buffer, size); $ txPrintf (stream, format, args...); $ return (int) stream.str().length(); //-V202 } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline std::string txFormat (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return ""; $ std::ostringstream stream; $ txPrintf (stream, format, args...); $ return stream.str(); } //----------------------------------------------------------------------------------------------------------------- template <typename... ArgsT> inline int txPrintf (const char* format, ArgsT... args) { $1 if (_TX_ARGUMENT_FAILED (&format)) return 0; $ return printf ("%s", txFormat (format, args...) .c_str()); } #endif //----------------------------------------------------------------------------------------------------------------- int _txPrintfCheck (const char* format, ...) tx_printfy (1); inline int _txPrintfCheck (const char*, ...) { return 0; } //} //================================================================================================================= //================================================================================================================= //{ txDialog methods implementation // Реализация методов класса txDialog // // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753 //================================================================================================================= #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<< txDialog::txDialog () : layout_ (NULL) {$1} //----------------------------------------------------------------------------------------------------------------- txDialog::txDialog (const Layout* layout) : layout_ (layout) {$1} //----------------------------------------------------------------------------------------------------------------- const txDialog::Layout* txDialog::setLayout (const Layout* layout) { $1 assert (layout); $ return ::std::swap (layout_, layout), layout; } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (WORD resourceID) { $1 const char* resName = (char*)(uintptr_t) resourceID; $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0; $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this); } //----------------------------------------------------------------------------------------------------------------- intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/) { $1 if (!layout) layout = layout_; $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога"), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки
13811  // нетрудно сделать свою аналогичную функцию без ограничений масштаба отображения. <s>Если ты дочитал до этого места,</s>
13812  // пересядь с иглы TXLib'а на поверхность GDI Win32, <s>хотя GDI тоже так себе, так что лучше заюзай GDI+, SFML, OpenGL
13813  // или DirectX, будет круто. Хотя это и сложнее.</s>
13814 
13815  // Пожалуйста, не надо бездумно копировать себе в программу код из TXLib'а. Осмыслите его и напишите свою функцию сами,
13816  // иначе вы породите невнятный паленый код и безнадежно испортите себе карму. :((
13817 
13818 $ return ok;
13819  }
13820 
13821 //-----------------------------------------------------------------------------------------------------------------
13822 
13823 bool txTransparentBlt (double xDest, double yDest, HDC sourceImage,
13824  COLORREF transColor /*= TX_BLACK*/, double xSource /*= 0*/, double ySource /*= 0*/)
13825  {
13826 $1 if (_TX_TXWINDOW_FAILED()) return false;
13827 
13828 $ return txTransparentBlt (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, transColor);
13829  }
13830 
13831 //-----------------------------------------------------------------------------------------------------------------
13832 
13833 bool txAlphaBlend (HDC destImage, double xDest, double yDest, double width, double height,
13834  HDC sourceImage, double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/)
13835  {
13836 $1 if (_TX_HDC_FAILED (destImage)) return false;
13837 $ if (_TX_HDC_FAILED (sourceImage)) return false;
13838 
13839 $ POINT size = txGetExtent (sourceImage);
13840 $ if (!width) width = size.x; //-V550
13841 $ if (!height) height = size.y; //-V550
13842 
13843 #if !defined (NDEBUG)
13844 
13845 $ if (!(0 <= xSource && xSource + width <= size.x &&
13846  0 <= ySource && ySource + height <= size.y))
13847  {
13848 $ SetLastError (ERROR_INVALID_DATA);
13849 $ TX_ERROR ("Прямоугольник копируемой области {%g, %g, %g, %g} не полностью лежит внутри изображения-источника {%d, %d, %d, %d}, "
13850  "функция txAlphaBlend() работать не будет.", xSource, ySource, xSource + width, ySource + height, 0, 0, (int) size.x, (int) size.y);
13851  }
13852 
13853 #endif
13854 
13855 $ if (alpha < 0) alpha = 0;
13856 $ if (alpha > 1) alpha = 1;
13857 
13858 $ BITMAP bmap = { 0, 0, 0, 0, 0, 24 };
13859 $ bool ok = !!Win32::GetObject (txGDI ((Win32::GetCurrentObject (sourceImage, OBJ_BITMAP)), sourceImage), sizeof (bmap), &bmap);
13860 
13861 $ BLENDFUNCTION blend = { AC_SRC_OVER, 0, (BYTE) ROUND (alpha * 255), (BYTE) ((bmap.bmBitsPixel == 32)? AC_SRC_ALPHA : 0) }; //-V112 //-V821 //-V2551
13862 
13863 $ if (Win32::AlphaBlend)
13864  {
13865 $ ok &= txGDI (!!(Win32::AlphaBlend (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height),
13866  sourceImage, ROUND (xSource), ROUND (ySource), ROUND (width), ROUND (height), blend)),
13867  destImage);
13868  }
13869  else
13870  {
13871 $ ok &= txGDI (!!(Win32::BitBlt (destImage, ROUND (xDest), ROUND (yDest), ROUND (width), ROUND (height),
13872  sourceImage, ROUND (xSource), ROUND (ySource), SRCCOPY)),
13873  destImage);
13874 $ ok = false; //-V519
13875  }
13876 
13877 $ return ok;
13878  }
13879 
13880 //-----------------------------------------------------------------------------------------------------------------
13881 
13882 bool txAlphaBlend (double xDest, double yDest, HDC sourceImage,
13883  double xSource /*= 0*/, double ySource /*= 0*/, double alpha /*= 1.0*/)
13884  {
13885 $1 if (_TX_TXWINDOW_FAILED()) return false;
13886 
13887 $ return txAlphaBlend (txDC(), xDest, yDest, 0, 0, sourceImage, xSource, ySource, alpha);
13888  }
13889 
13890 //-----------------------------------------------------------------------------------------------------------------
13891 
13892 HDC txUseAlpha (HDC image)
13893  {
13894 $1 if (_TX_HDC_FAILED (image)) return NULL;
13895 
13896 $ HBITMAP bitmap = (HBITMAP) Win32::GetCurrentObject (image, OBJ_BITMAP);
13897 $ if (!bitmap) return NULL;
13898 
13899 $ DIBSECTION dib = {};
13900 $ Win32::GetObject (bitmap, sizeof (dib), &dib) asserted;
13901 
13902 $ POINT size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight };
13903 $ BITMAPINFO info = {{ sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB }};
13904 $ RGBQUAD* buf = NULL;
13905 
13906 $ bool isDIB = (dib.dsBm.bmPlanes == 1 &&
13907  dib.dsBm.bmBitsPixel == sizeof (RGBQUAD) * 8 &&
13908  dib.dsBmih.biCompression == DIB_RGB_COLORS &&
13909  dib.dsBm.bmBits);
13910 $ if (!isDIB)
13911  {
13912 $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121
13913 $ if (!buf) return NULL;
13914 
13915 $ Win32::GetDIBits (image, bitmap, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted;
13916  }
13917  else
13918  {
13919 $ buf = (RGBQUAD*) dib.dsBm.bmBits;
13920  }
13921 
13922 $ for (int y = 0; y < size.y; y++)
13923  for (int x = 0; x < size.x; x++)
13924  {
13925  RGBQUAD* color = &buf [x + y * size.x]; // Get color at (x, y) within image buffer //-V108
13926 
13927  color->rgbRed = (BYTE) ROUND (color->rgbRed * color->rgbReserved / 255.0);
13928  color->rgbGreen = (BYTE) ROUND (color->rgbGreen * color->rgbReserved / 255.0);
13929  color->rgbBlue = (BYTE) ROUND (color->rgbBlue * color->rgbReserved / 255.0);
13930  }
13931 
13932 $ if (!isDIB)
13933  {
13934 $ Win32::SetDIBitsToDevice (image, 0, 0, size.x, size.y, 0, 0, 0, size.y, buf, &info, DIB_RGB_COLORS) asserted;
13935 
13936 $ delete[] buf;
13937  }
13938 
13939 $ return image;
13940  }
13941 
13942 //-----------------------------------------------------------------------------------------------------------------
13943 
13944 bool txSaveImage (const char filename[], HDC dc /*= txDC()*/)
13945  {
13946 $1 if (_TX_ARGUMENT_FAILED (filename)) return false;
13947 $ if (_TX_DEFAULT_HDC_FAILED (dc)) return false;
13948 
13949 $ POINT size = txGetExtent (dc);
13950 
13951 $ size_t szHdrs = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), //-V119
13952  szImg = (size.x * size.y) * sizeof (RGBQUAD); //-V104
13953 
13954 $ BITMAP bmap = {};
13955 $ BITMAPFILEHEADER hdr = { 0x4D42 /* 'MB' */, (DWORD) (szHdrs + szImg), 0, 0, (DWORD) szHdrs }; //-V202
13956 $ BITMAPINFOHEADER info = { sizeof (info), size.x, size.y, 1, (WORD) (sizeof (RGBQUAD) * 8), BI_RGB };
13957 
13958 $ RGBQUAD* buf = NULL;
13959 $ bool ok = true;
13960 
13961 $ ok &= !!Win32::GetObject (Win32::GetCurrentObject (dc, OBJ_BITMAP), sizeof (bmap), &bmap);
13962 
13963  if (!ok) {$ return false; }
13964 
13965 $ if (!bmap.bmBits)
13966  {
13967 $ buf = new (std::nothrow) RGBQUAD [size.x * size.y]; //-V121
13968 $ ok &= (buf != NULL);
13969 
13970 $ int res = Win32::GetDIBits (dc, (HBITMAP) Win32::GetCurrentObject (dc, OBJ_BITMAP), 0, size.y,
13971  buf, (BITMAPINFO*) &info, DIB_RGB_COLORS);
13972 
13973  if (res == ERROR_INVALID_PARAMETER) {$ SetLastError (res); }
13974 
13975 $ ok &= !!res;
13976  }
13977  else
13978  {
13979 $ buf = (RGBQUAD*) bmap.bmBits;
13980  }
13981 
13982 $ FILE* f = NULL;
13983 $ if (ok) fopen_s (&f, filename, "wb");
13984 $ ok &= (f != NULL);
13985 
13986 $ if (ok) ok &= (fwrite (&hdr, sizeof (hdr), 1, f) == 1); //-V575 //-V595
13987 $ if (ok) ok &= (fwrite (&info, sizeof (info), 1, f) == 1);
13988 $ if (ok) ok &= (fwrite (buf, szImg, 1, f) == 1); //-V575
13989 
13990 $ ok &= (f && fclose (f) == 0);
13991 
13992 $ if (!bmap.bmBits)
13993  {
13994 $ delete[] buf;
13995 $ buf = NULL;
13996  }
13997 
13998 $ return ok;
13999  }
14000 
14001 //-----------------------------------------------------------------------------------------------------------------
14002 
14003 double txSleep (double time)
14004  {
14005 $1 LARGE_INTEGER start = {};
14006 $ QueryPerformanceCounter (&start) asserted;
14007 
14008 $ LARGE_INTEGER freq = {};
14009 $ QueryPerformanceFrequency (&freq) asserted;
14010 
14011 $ int lock = _txCanvas_RefreshLock;
14012 $ _txCanvas_RefreshLock = 0;
14013 
14014 $ HWND wnd = txWindow();
14015  if (wnd) {$ RedrawWindow (wnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_UPDATENOW); }
14016 
14017 $ Sleep (ROUND ((time >= 0)? time : 0));
14018 
14019 $ _txCanvas_RefreshLock = lock;
14020 
14021 $ LARGE_INTEGER stop = {};
14022 $ QueryPerformanceCounter (&stop) asserted;
14023 
14024 $ return 1000.0 * (double) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart;
14025  }
14026 
14027 //-----------------------------------------------------------------------------------------------------------------
14028 
14029 bool txLock (bool wait /*= true*/)
14030  {
14031 $0 if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0);
14032 
14033 $ if (wait) {$ return EnterCriticalSection (&_txCanvas_LockBackBuf), true; } //-V1048
14034  else {$ return !!TryEnterCriticalSection (&_txCanvas_LockBackBuf); }
14035  }
14036 
14037 //-----------------------------------------------------------------------------------------------------------------
14038 
14039 bool txUnlock()
14040  {
14041 $0 LeaveCriticalSection (&_txCanvas_LockBackBuf);
14042 
14043 $ if (_txCanvas_RefreshLock <= 0 || _txExit) Sleep (0);
14044 $ return false;
14045  }
14046 
14047 #endif // TX_COMPILED
14048 
14049 //-----------------------------------------------------------------------------------------------------------------
14050 
14051 template <typename T>
14052 inline T txUnlock (T value)
14053  {
14054 $1 txUnlock();
14055 $ return value;
14056  }
14057 
14058 //-----------------------------------------------------------------------------------------------------------------
14059 
14060 inline void txRedrawWindow()
14061  {
14062 $1 txSleep (0);
14063  }
14064 
14065 //-----------------------------------------------------------------------------------------------------------------
14066 
14067 inline int txUpdateWindow (int update /*= true*/)
14068  {
14069 $1 return _txCanvas_SetRefreshLock (update >= 0? (int) !update : -update);
14070  }
14071 
14072 //-----------------------------------------------------------------------------------------------------------------
14073 
14074 inline int txBegin()
14075  {
14076 $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock + 1);
14077 
14078 $ return _txCanvas_RefreshLock;
14079  }
14080 
14081 //-----------------------------------------------------------------------------------------------------------------
14082 
14083 inline int txEnd()
14084  {
14085 $1 _txCanvas_SetRefreshLock (_txCanvas_RefreshLock - 1);
14086 
14087 $ return _txCanvas_RefreshLock;
14088  }
14089 
14090 //-----------------------------------------------------------------------------------------------------------------
14091 
14092 inline POINT txMousePos()
14093  {
14094 $1 POINT pos = {};
14095 $ GetCursorPos (&pos);
14096 
14097 $ if (txWindow())
14098  {$ ScreenToClient (txWindow(), &pos); }
14099 
14100 $ return pos;
14101  }
14102 
14103 //-----------------------------------------------------------------------------------------------------------------
14104 
14105 inline double txMouseX()
14106  {
14107  return (double) txMousePos() .x;
14108  }
14109 
14110 //-----------------------------------------------------------------------------------------------------------------
14111 
14112 inline double txMouseY()
14113  {
14114  return (double) txMousePos() .y;
14115  }
14116 
14117 //-----------------------------------------------------------------------------------------------------------------
14118 
14119 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
14120 
14121 unsigned txMouseButtons()
14122  {
14123 $1 HWND txWnd = txWindow();
14124 $ HWND foreground = GetForegroundWindow();
14125 
14126 $ if ((txWnd && (foreground == txWnd)) ||
14127  (!txWnd && (foreground == Win32::GetConsoleWindow())))
14128  {
14129 $ return ((GetAsyncKeyState (VK_LBUTTON) & 0x8000) >> 15) | // MSB to bit 0
14130  ((GetAsyncKeyState (VK_RBUTTON) & 0x8000) >> 14) | // MSB to bit 1
14131  ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) >> 13); // MSB to bit 2
14132  }
14133  else
14134  {$ return 0; }
14135  }
14136 
14137 //-----------------------------------------------------------------------------------------------------------------
14138 
14139 unsigned txSetConsoleAttr (unsigned color /*= FOREGROUND_LIGHTGRAY*/)
14140  {
14141  unsigned oldAttr = txGetConsoleAttr();
14142 
14143  SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), (WORD) color);
14144  SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (WORD) color);
14145 
14146  return oldAttr;
14147  }
14148 
14149 //-----------------------------------------------------------------------------------------------------------------
14150 
14151 unsigned txGetConsoleAttr()
14152  {
14153  CONSOLE_SCREEN_BUFFER_INFO con = {};
14154  con.wAttributes = FOREGROUND_LIGHTGRAY;
14155 
14156  GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) ||
14157  GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &con);
14158 
14159  return con.wAttributes;
14160  }
14161 
14162 //-----------------------------------------------------------------------------------------------------------------
14163 
14164 POINT txSetConsoleCursorPos (double x, double y)
14165  {
14166 $1 POINT fontSz = txGetConsoleFontSize();
14167 
14168 $ CONSOLE_SCREEN_BUFFER_INFO con = {};
14169 $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted;
14170 
14171 $ COORD pos = { (short) ROUND (1.0 * x / fontSz.x + con.srWindow.Left),
14172  (short) ROUND (1.0 * y / fontSz.y + con.srWindow.Top ) };
14173 
14174 $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos) asserted;
14175 
14176 $ POINT prev = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x),
14177  ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) };
14178 $ return prev;
14179  }
14180 
14181 //-----------------------------------------------------------------------------------------------------------------
14182 
14183 POINT txGetConsoleCursorPos()
14184  {
14185 $1 POINT fontSz = txGetConsoleFontSize();
14186 
14187 $ CONSOLE_SCREEN_BUFFER_INFO con = {};
14188 $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted;
14189 
14190 $ POINT pos = { ROUND ((con.dwCursorPosition.X - con.srWindow.Left) * fontSz.x),
14191  ROUND ((con.dwCursorPosition.Y - con.srWindow.Top ) * fontSz.y) };
14192 $ return pos;
14193  }
14194 
14195 //-----------------------------------------------------------------------------------------------------------------
14196 
14197 POINT txGetConsoleExtent()
14198  {
14199 $1 CONSOLE_SCREEN_BUFFER_INFO con = {};
14200 $ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &con) asserted;
14201 
14202 $ POINT size = { con.srWindow.Right - con.srWindow.Left + 1,
14203  con.srWindow.Bottom - con.srWindow.Top + 1 };
14204 $ return size;
14205  }
14206 
14207 //-----------------------------------------------------------------------------------------------------------------
14208 
14209 bool txClearConsole()
14210  {
14211 $1 HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE);
14212 
14213 $ CONSOLE_SCREEN_BUFFER_INFO con = {};
14214 $ GetConsoleScreenBufferInfo (out, &con) asserted;
14215 
14216 $ COORD start = {con.srWindow.Left, con.srWindow.Top};
14217 
14218 $ DWORD len = (con.srWindow.Right - con.srWindow.Left + 1) *
14219  (con.srWindow.Bottom - con.srWindow.Top + 1);
14220 
14221 $ DWORD written = 0;
14222 $ FillConsoleOutputCharacter (out, 0x20 /*' '*/, len, start, &written) asserted; //-V112
14223 $ FillConsoleOutputAttribute (out, con.wAttributes, len, start, &written) asserted;
14224 
14225 $ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), start) asserted;
14226 
14227 $ return written == len;
14228  }
14229 
14230 //-----------------------------------------------------------------------------------------------------------------
14231 
14232 POINT txGetConsoleFontSize()
14233  {
14234 $1 Win32::CONSOLE_FONT_INFO font = {0, {8, 16}};
14235 
14236 $ _TX_CALL (Win32::GetCurrentConsoleFont, (GetStdHandle (STD_OUTPUT_HANDLE), false, &font));
14237 
14238 $ SIZE size = { font.dwFontSize.X, font.dwFontSize.Y };
14239  if (_txCanvas_BackBuf[1]) {$ txGDI (Win32::GetTextExtentPoint32 (_txCanvas_BackBuf[1], "W", 1, &size), txDC()); } //-V501
14240 
14241  if (size.cx == 0) {$ size.cx = 1; }
14242  if (size.cy == 0) {$ size.cy = 1; }
14243 
14244 $ POINT sizeFont = { size.cx, size.cy };
14245 $ return sizeFont;
14246  }
14247 
14248 //-----------------------------------------------------------------------------------------------------------------
14249 
14250 bool txTextCursor (bool blink /*= true*/)
14251  {
14252 $1 bool old = _txConsole_IsBlinking;
14253 
14254 $ _txConsole_IsBlinking = blink;
14255 
14256 $ return old;
14257  }
14258 
14259 //-----------------------------------------------------------------------------------------------------------------
14260 
14261 bool txPlaySound (const char filename[] /*= NULL*/, DWORD mode /*= SND_ASYNC*/)
14262  {
14263 $1 mode |= SND_FILENAME | SND_NODEFAULT | SND_NOWAIT;
14264 $ if (mode & SND_LOOP) mode = (mode & ~SND_SYNC) | SND_ASYNC;
14265 
14266 $ if (!filename) mode = SND_PURGE;
14267 
14268 $ return !!Win32::PlaySound (filename, NULL, mode);
14269  }
14270 
14271 //-----------------------------------------------------------------------------------------------------------------
14272 
14273 int txSpeak (const char* text, ...)
14274  {
14275 $1 bool verbose = false; (void) verbose;
14276 $ bool async = false; (void) async;
14277 
14278 $ for (; text && *text; text++)
14279  {
14280  if (*text == '\a') {$ async = true; }
14281  else if (*text == '\v') {$ verbose = true; }
14282  else break;
14283  }
14284 
14285 $ char textA [_TX_BUFSIZE] = "You asked to speak empty text. I would rather say that TX Library is cool! Cats rules!";
14286 
14287 $ va_list arg; va_start (arg, text);
14288  if (text && *text) {$ _tx_vsnprintf_s (textA, sizeof (textA) - 1, text, arg); }
14289 $ va_end (arg);
14290 
14291  if (text && verbose) {$ printf ("%s", textA); }
14292 
14293 #ifdef TX_USE_SPEAK
14294 
14295 $ int time = GetTickCount();
14296 
14297 $ static wchar_t textW [_TX_BUFSIZE * sizeof (wchar_t)] = L"";
14298 $ MultiByteToWideChar (_TX_CODEPAGE, 0, textA, -1, textW, sizearr (textW));
14299 
14300 $ static ISpVoice* voice = NULL;
14301 
14302 $ if (text && !voice)
14303  {
14304 $ HRESULT res = Win32::CoInitialize (NULL);
14305  if (res == S_OK) {$ Win32::CoCreateInstance (Win32::CLSID_SpVoice, NULL, CLSCTX_ALL, Win32::IID_ISpVoice, (void**) &voice); }
14306  }
14307 
14308 $ if (text && voice)
14309  {
14310 $ Win32::_fpreset();
14311 $ voice->Speak (textW, SPF_PERSIST_XML | SPF_PURGEBEFORESPEAK | ((*textW == '<')? SPF_IS_XML : 0) | (async? SPF_ASYNC : 0), NULL);
14312 $ tx_fpreset();
14313  }
14314 
14315 $ if (!text && voice)
14316  {
14317 $ voice->Release();
14318 $ voice = NULL;
14319 
14320 $ Win32::CoUninitialize();
14321  }
14322 
14323 $ return (voice)? GetTickCount() - time : -1;
14324 
14325 #else
14326 
14327 $ if (text)
14328  {
14329 $ unsigned oldAttr = txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK);
14330 
14331 $ txNotifyIcon (NIIF_ERROR, "txSpeak(): Не могу произнести (нужен TX_USE_SPEAK, см. TXLib Help)", "\n" "%s", textA);
14332 
14333 $ txSetConsoleAttr (oldAttr);
14334  }
14335 
14336 $ return -1;
14337 
14338 #endif
14339  }
14340 
14341 //-----------------------------------------------------------------------------------------------------------------
14342 
14343 intptr_t txPlayVideo (int x, int y, int width, int height, const char fileName[],
14344  double zoom /*= 0*/, double gain /*= 1*/, HWND wnd /*= txWindow()*/)
14345  {
14346 $1 if (wnd && wnd == txWindow() && _TX_TXWINDOW_FAILED()) return -1;
14347 
14348 $ int time = GetTickCount(); //-V2551
14349 
14350 $ static char processUID [64] = "";
14351  if (!*processUID)
14352  {
14353 $ FILETIME startTime = {}, null = {};
14354 $ GetProcessTimes (GetCurrentProcess(), &startTime, &null, &null, &null) asserted;
14355 $ _snprintf_s (processUID, sizeof (processUID) - 1, "TXLib[%08X%08X]::txPlayVideo",
14356  (unsigned) startTime.dwHighDateTime, (unsigned) startTime.dwLowDateTime) < (int) sizeof (processUID) asserted;
14357  }
14358 
14359 $ if (!fileName)
14360  {
14361 $ _txTaskKill ("vlc.exe", processUID, 0); // Kill'em all, by command line pattern
14362 $ return 0;
14363  }
14364 
14365 $ static const char* vlcPath = _txPlayVideo_FindVLC();
14366 
14367 $ if (!vlcPath || _access (vlcPath, 0) != 0)
14368  {
14369 $ static int once = false; //-V601
14370 
14371 $ if (*fileName && !once++)
14372  {$ txOutputDebugPrintf ("\a" "Не найден видеопроигрыватель VideoLAN (vlc.exe). Cкачайте его с сайта VideoLAN.org "
14373  "и установите. Без установки VideoLAN видео воспроизводиться не будет :(\n\n"
14374  "--\n" "Всегда Ваша, функция " /* как бы */ "txPlayVideo()...\n"
14375  "P.S. См. мое описание в TXLib Help."); }
14376 $ return INT_MIN; //-V109
14377  }
14378 
14379 $ bool async = false;
14380  if (*fileName == '\a') {$ async = true; fileName++; }
14381 
14382 $ RECT rect = {};
14383  if (wnd) {$ GetClientRect (wnd, &rect); }
14384 
14385  if (!width) {$ width = rect.right; }
14386  if (!height) {$ height = rect.bottom; }
14387 
14388  // Create a child window to hold the video stream
14389 
14390 $ const char* errPos = "ВНЕЗАПНО";
14391 
14392 $ volatile HWND child = NULL;
14393 $ if (wnd && (wnd == txWindow()))
14394  {
14395 $ const char* wndClass = txRegisterClass ("txPlayVideo", _txPlayVideo_WndProc, 0, NULL_BRUSH, 1);
14396 
14397 $ static int number = 1;
14398 $ CREATESTRUCT createData = { NULL, NULL, (HMENU) (size_t) number++, txWindow(), height, width, y, x,
14399  WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, __func__, wndClass };
14400 $ child = txCreateExtraWindow (createData);
14401 $ if (!child)
14402  {
14403 $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s",
14404  strstr (_txError (NULL, 0, NULL, 0, "\f" "Не могу создать окно для видео :("), errPos));
14405 $ return INT_MIN+3; //-V109
14406  }
14407 
14408 $ BringWindowToTop (child);
14409 
14410 $ wnd = child;
14411  }
14412 
14413  // Build the command line
14414 
14415  if (!zoom && !wnd) {$ zoom = 1; }
14416 
14417 $ char sZoom [64] = "--autoscale";
14418  if (zoom) {$ _snprintf_s (sZoom, sizeof (sZoom) - 1, "--no-autoscale --zoom=%.10g", zoom) < (int) sizeof (sZoom) asserted; } //-V550
14419 
14420 $ static char cmd [MAX_PATH*2 + 1024] = "";
14421 
14422 $ _snprintf_s (cmd, sizeof (cmd) - 1, "\"%s\" \"%s\" vlc://quit"
14423 
14424  " %s --gain=%.10g --drawable-hwnd=%p --video-title=\"%s\" --logfile=%s"
14425 
14426  " --live-caching=500 --network-caching=500 --quiet-synchro --no-embedded-video --file-logging"
14427 
14428  " --ignore-config --reset-config --no-one-instance --play-and-exit"
14429  " --intf=dummy --dummy-quiet --quiet --no-video-deco --no-video-title-show --no-stats --no-sub-autodetect-file"
14430  " --no-disable-screensaver --no-snapshot-preview --no-auto-preparse --no-mouse-events --no-keyboard-events",
14431 
14432  vlcPath, (*fileName? fileName : "fileName"), sZoom, gain, (void*) wnd, processUID, _txLogName) < (int) sizeof (cmd) asserted;
14433 
14434 $ txOutputDebugPrintf ("txPlayVideo (%d, %d, %d, %d, \"%s\", %g, %g, %p): [%s]\n\n",
14435  x, y, width, height, fileName, zoom, gain, (void*) wnd, cmd);
14436 $ if (!*fileName)
14437  {
14438  if (child) {$ txDestroyWindow (child); }
14439 $ return (intptr_t) cmd;
14440  }
14441 
14442 $ if (!strstr (fileName, "://") && _access (fileName, 0) != 0)
14443  {
14444 $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "\n" "%s",
14445  strstr (_txError (NULL, 0, NULL, 0, "\f" "Не найден файл \"%s\"", fileName), errPos));
14446 
14447  if (child) {$ txDestroyWindow (child); }
14448 $ return INT_MIN+1; //-V109
14449  }
14450 
14451  // Run VLC, run
14452 
14453 $ PROCESS_INFORMATION vlc = {};
14454 $ STARTUPINFO start = { sizeof (start) };
14455 $ DWORD ret = 0;
14456 
14457 $ if (CreateProcess (NULL, cmd, NULL, NULL, true, 0, NULL, NULL, &start, &vlc) &&
14458  vlc.hProcess && vlc.hThread)
14459  {
14460 $ if (child)
14461  {
14462 $ assert (wnd == child); //-V547
14463 $ SetWindowLongPtr (wnd, GWLP_USERDATA, (LONG_PTR) vlc.hProcess); //-V107
14464  }
14465 
14466 $ if (!async)
14467  {
14468 $ WaitForSingleObject (vlc.hProcess, INFINITE);
14469 $ GetExitCodeProcess (vlc.hProcess, &ret) asserted;
14470  }
14471 
14472 $ if (!child)
14473  {
14474 $ CloseHandle (vlc.hProcess) asserted;
14475  }
14476 
14477 $ CloseHandle (vlc.hThread) asserted;
14478 
14479 $ return (async? (intptr_t) wnd : (ret == 0)? time - GetTickCount() : - (int) ret); //-V105
14480  }
14481  else
14482  {
14483 $ txNotifyIcon (NIIF_ERROR, "txPlayVideo() сообщает", "%s",
14484  strstr (_txError (NULL, 0, NULL, 0, "\f" "Ошибка запуска VideoLAN (%s)", cmd), errPos));
14485 $ if (child)
14486  {$ txDestroyWindow (child); }
14487 
14488 $ return INT_MIN+4; //-V112 //-V109
14489  }
14490 
14491  #undef PROCESS_UID_
14492  }
14493 
14494 //-----------------------------------------------------------------------------------------------------------------
14495 
14496 intptr_t txPlayVideo (const char fileName[], double zoom /*= 0*/, double gain /*= 0*/, HWND wnd /*= txWindow()*/)
14497  {
14498 $1 return txPlayVideo (0, 0, 0, 0, fileName, zoom, gain, wnd);
14499  }
14500 
14501 //-----------------------------------------------------------------------------------------------------------------
14502 
14503 LRESULT CALLBACK _txPlayVideo_WndProc (HWND wnd, UINT msg, WPARAM wpar, LPARAM lpar)
14504  {
14505  const UINT_PTR checkTimer = 1;
14506 
14507  switch (msg)
14508  {
14509  case WM_CREATE:
14510  {
14511 $1 SetTimer (wnd, checkTimer, 5*_txWindowUpdateInterval, NULL) asserted;
14512  }
14513  break;
14514 
14515  case WM_DESTROY:
14516  {
14517 $1 KillTimer (wnd, checkTimer) asserted;
14518 
14519 $ HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA);
14520 
14521 $ if (vlc)
14522  {
14523 $ Win32::TerminateProcess (vlc, 0);
14524 
14525 $ CloseHandle (vlc) asserted;
14526 
14527 $ SetWindowLongPtr (wnd, GWLP_USERDATA, 0);
14528  }
14529  }
14530  break;
14531 
14532  case WM_TIMER:
14533  {
14534  HANDLE vlc = (HANDLE)(uintptr_t) GetWindowLongPtr (wnd, GWLP_USERDATA);
14535 
14536  if (vlc && WaitForSingleObject (vlc, 0) != WAIT_TIMEOUT)
14537  {
14538 $1 DestroyWindow (wnd) asserted;
14539  }
14540  }
14541  break;
14542 
14543  default: //-V2522
14544  break;
14545  }
14546 
14547  return DefWindowProc (wnd, msg, wpar, lpar);
14548  }
14549 
14550 //-----------------------------------------------------------------------------------------------------------------
14551 
14552 const char* _txPlayVideo_FindVLC()
14553  {
14554 $1 static char vlcPath [MAX_PATH] = "";
14555 
14556 $ if (SearchPath (NULL, "vlc.bat", NULL, sizeof (vlcPath), vlcPath, NULL))
14557  {
14558  if (_access (vlcPath, 0) == 0) {$ return vlcPath; }
14559  }
14560 
14561 $ if (SearchPath (NULL, "vlc.exe", NULL, sizeof (vlcPath), vlcPath, NULL))
14562  {
14563  if (_access (vlcPath, 0) == 0) {$ return vlcPath; }
14564  }
14565 
14566 $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", NULL, vlcPath, sizeof (vlcPath)))
14567  {
14568  if (_access (vlcPath, 0) == 0) {$ return vlcPath; }
14569  }
14570 
14571 $ if (txRegQuery ("HKLM\\Software\\VideoLAN\\VLC", "InstallDir", vlcPath, sizeof (vlcPath)))
14572  {
14573 $ strncat_s (vlcPath, sizeof (vlcPath) - 1, "\\vlc.exe", INT_MAX);
14574 
14575  if (_access (vlcPath, 0) == 0) {$ return vlcPath; }
14576  }
14577 
14578 $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files" "\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106
14579  {
14580  if (_access (vlcPath, 0) == 0) {$ return vlcPath; }
14581  }
14582 
14583 $ strncpy_s (vlcPath, sizeof (vlcPath), "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", UINT_MAX); //-V106
14584  {
14585  if (_access (vlcPath, 0) == 0) {$ return vlcPath; }
14586  }
14587 
14588 $ return NULL;
14589  }
14590 
14591 //-----------------------------------------------------------------------------------------------------------------
14592 
14593 HRESULT txSetProgress (double percent, unsigned type /*= TBPF_NORMAL*/, HWND wnd /*= NULL*/)
14594  {
14595 $1 static double oldPercent = 100;
14596 
14597  if (percent < 0) {$ percent = MIN (oldPercent, 100); }
14598  else {$ oldPercent = percent; }
14599 
14600 $ HRESULT res = S_FALSE;
14601 
14602  #if defined (__ITaskbarList3_INTERFACE_DEFINED__)
14603 
14604 $ HRESULT init = Win32::CoInitialize (NULL);
14605 
14606 $ bool ok = true;
14607 $ res = S_OK;
14608 
14609 $ ITaskbarList3* taskbar = NULL;
14610  if (ok) {$ res = Win32::CoCreateInstance (Win32::CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, Win32::IID_ITaskbarList3, (void**) &taskbar); }
14611 $ ok &= !!taskbar && (res == S_OK);
14612 
14613  if (!wnd) {$ wnd = txWindow(); }
14614  if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); }
14615  if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); }
14616 
14617  if (wnd == txWindow()) {$ wnd = Win32::GetConsoleWindow(); }
14618  if (ok && taskbar) {$ res = taskbar->SetProgressValue (wnd, ROUND (percent), 100); ok &= (res == S_OK); }
14619  if (ok && taskbar) {$ res = taskbar->SetProgressState (wnd, (TBPFLAG) type); ok &= (res == S_OK); }
14620 
14621  if (taskbar) {$ taskbar->Release(); }
14622 
14623  if (init == S_OK) {$ Win32::CoUninitialize(); }
14624 
14625  #endif
14626 
14627  (void) type; (void) wnd;
14628 
14629 $ return res;
14630  }
14631 
14632 #endif // TX_COMPILED
14633 
14634 //-----------------------------------------------------------------------------------------------------------------
14635 
14636 // +--<<< Это не те символы, что вы ищете :)
14637 // V Полезно смотреть не только вверх, но и вниз
14638 
14639 inline WNDPROC txSetWindowsHook (WNDPROC wndProc /*= NULL*/)
14640  {
14641 $1 WNDPROC old = _txAltWndProc; _txAltWndProc = wndProc;
14642 $ return old;
14643  }
14644 
14645 //-----------------------------------------------------------------------------------------------------------------
14646 
14647 // +--<<< А это, наконец, искомое определение этой функции.
14648 // | Смотрите по сторонам! Нужная вам функция где-то рядом.
14649 // |
14650 // v
14652  {
14653  txMessageBox ("Это запланированная ошибка. Такое бывает. Вы хотели вызвать:\n\n"
14654 
14655  "txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()\n\n"
14656 
14657  "Хоть вы долго [копировали]набирали это имя, на самом деле эта функция не реализована. "
14658  "Есть другая функция, которая убирает авто-паузу в конце программы, но в хелпе про нее не написано.\n\n"
14659 
14660  "Но не все так плохо. Определение нужной функции есть в исходных текстах TXLib.h, оно лежит рядом "
14661  "с определением той функции с длинным названием, которую вы сейчас вызвали.\n\n"
14662 
14663  "Нажмите в редакторе Ctrl+O, найдите и откройте файл TXLib.h (он лежит в папке, куда вы "
14664  "установили TXLib), затем нажмите Ctrl+F и ищите \"txIDontWant\". Удачи!\n\n",
14665 
14666  "Не получилось", MB_ICONSTOP);
14667 
14668  // The truth is out there... (C++files)
14669 
14670  return false;
14671  }
14672 
14673 //-----------------------------------------------------------------------------------------------------------------
14674 
14675 // Bingo! Now you are learned to use the Source, Luke. And may the Source be with you.
14676 
14677 inline bool txDisableAutoPause()
14678  {
14679  _txExit = true;
14680  return true;
14681  }
14682 
14683 // P.S. This library contains more undocumented functions. Search them via "Luke" keyword.
14684 
14685 //-----------------------------------------------------------------------------------------------------------------
14686 
14687 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
14688 
14689 void _txDump (const void* address, const char name[] /*= "_txDump()"*/, bool pause /*= true*/)
14690  {
14691 $1 assert (!_txIsBadReadPtr (address));
14692 
14693 $ const unsigned char* addr = (const unsigned char*) address;
14694 
14695 $ const int stdout_fileno = 1; // Not all g++ packages contain STDOUT_FILENO
14696 $ const int _o_u16text = 0x00020000; // and _O_U16TEXT
14697 
14698 $ bool istty = _txIsTTY (1);
14699 
14700 $ int mode = _O_TEXT;
14701 $ int oldMode = _setmode (stdout_fileno, mode);
14702 
14703 $ unsigned oldCP = GetConsoleOutputCP();
14704 $ unsigned cp = 1251; SetConsoleOutputCP (cp); //-V581
14705 
14706 $ unsigned attr = txGetConsoleAttr();
14707 
14708 $ txSetConsoleAttr (FOREGROUND_WHITE);
14709 $ printf ("\n%*.*s ", (int) sizeof (address) * 2, (int) sizeof (address) * 2, ((name)? name : ""));
14710 
14711 $ txSetConsoleAttr (FOREGROUND_YELLOW);
14712 $ for (unsigned x = 0; x < 16; x++) printf ("%02X ", x);
14713 $ for (unsigned x = 0; x < 16; x++) printf ("%X", x);
14714 
14715 $ const wchar_t* xlat[33] = {L"\xB7" /* 00 - NUL - NULL */, L"\x263A" /* 01 - SOH - Start of header */,
14716  L"\x263B" /* 02 - STX - Start of text */, L"\x2665" /* 03 - ETX - End of text */,
14717  L"\x2666" /* 04 - EOT - End of transm. */, L"\x2663" /* 05 - ENQ - Enquiry */,
14718  L"\x2660" /* 06 - ACK - Acknowledgment */, L"\x2022" /* 07 - BEL - Bell */,
14719  L"\x25D8" /* 08 - BS - Backspace */, L"\x25CB" /* 09 - HT - Horizontal tab */,
14720  L"\x25D9" /* 10 - LF - Line feed */, L"\x2642" /* 11 - VT - Vertical tab */,
14721  L"\x2640" /* 12 - FF - Form feed */, L"\x266A" /* 13 - CR - Carriage return */,
14722  L"\x266B" /* 14 - SO - Shift out */, L"\x263C" /* 15 - SI - Shift in */,
14723  L"\x25BA" /* 16 - DLE - Data link escape */, L"\x25C4" /* 17 - DC1 - Device control 1 */,
14724  L"\x2195" /* 18 - DC2 - Device control 2 */, L"\x203C" /* 19 - DC3 - Device control 3 */,
14725  L"\xB6" /* 20 - DC4 - Device control 4 */, L"\xA7" /* 21 - NAK - Negative ACK */,
14726  L"\x25AC" /* 22 - SYN - Synchronous idle */, L"\x21A8" /* 23 - ETB - End of transm. block */,
14727  L"\x2191" /* 24 - CAN - Cancel */, L"\x2193" /* 25 - EM - End of medium */,
14728  L"\x2192" /* 26 - SUB - Substitute */, L"\x2190" /* 27 - ESC - Escape */,
14729  L"\x221F" /* 28 - FS - File separator */, L"\x2194" /* 29 - GS - Group separator */,
14730  L"\x25B2" /* 30 - RS - Record separator */, L"\x25BC" /* 31 - US - Unit separator */,
14731  L"\x20" /* 32 - Space */};
14732 
14733 $ for (int y = 0; y < 16; y++, addr += 16)
14734  {
14735  if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581
14736  (void)_setmode (stdout_fileno, mode = oldMode);
14737 
14738  txSetConsoleAttr (FOREGROUND_YELLOW);
14739 
14740  printf ("\n" "%*p ", (int) sizeof (address) * 2, addr);
14741 
14742  int color = FOREGROUND_LIGHTGREEN;
14743 
14744  for (unsigned x = 0; x < 16; x++)
14745  {
14746  txSetConsoleAttr (color + x/4%2); //-V112
14747  printf ("%02X ", addr[x]);
14748  }
14749 
14750  for (unsigned x = 0; x < 16; x++)
14751  {
14752  txSetConsoleAttr (color + x/4%2); //-V112
14753 
14754  unsigned char ch = addr[x];
14755 
14756  if (ch >= sizearr (xlat) || !istty)
14757  {
14758  if (cp != oldCP) SetConsoleOutputCP (cp = oldCP); //-V581
14759  if (mode != oldMode) (void)_setmode (stdout_fileno, mode = oldMode);
14760 
14761  printf ("%c", !strchr ("\t\r\n", ch)? ch : ' ');
14762  }
14763  else
14764  {
14765  if (cp != 1251) SetConsoleOutputCP (cp = 1251); //-V581
14766  if (mode != _o_u16text) (void)_setmode (stdout_fileno, mode = _o_u16text);
14767 
14768  wprintf (L"%lls", xlat[ch]);
14769  }
14770  }
14771  }
14772 
14773 $ (void)_setmode (stdout_fileno, oldMode);
14774 $ printf ("\n");
14775 
14776 $ if (pause && istty)
14777  {
14778 $ txSetConsoleAttr (FOREGROUND_DARKGRAY);
14779 $ txPause ("\v%-*s CodePage = %5u", (int) sizeof (void*) * 2 + 16*3, "[Нажмите любую клавишу для продолжения]", oldCP);
14780  }
14781 
14782 $ txSetConsoleAttr (FOREGROUND_LIGHTGRAY);
14783 $ printf ("\n");
14784 
14785 $ txSetConsoleAttr (attr);
14786 $ SetConsoleOutputCP (oldCP);
14787  }
14788 
14789 //-----------------------------------------------------------------------------------------------------------------
14790 
14791 void _txStackBackTrace (const char file[] /*= "?"*/, int line /*= 0*/, const char func[] /*= "?"*/,
14792  bool readSource /*= true*/)
14793  {
14794 $1 unsigned attr = txGetConsoleAttr();
14795 $ txSetConsoleAttr (FOREGROUND_LIGHTCYAN);
14796 
14797 $ fprintf (stderr, "\n" "--------------------------------------------------\n"
14798  "Трассировка стека из \"%s\" at %s:%d:\n\n"
14799  "%s\n\n"
14800  "--------------------------------------------------\n\n",
14801  func, file, line, _txCaptureStackBackTrace (1, readSource));
14802 
14803 $ txSetConsoleAttr (attr);
14804  }
14805 
14806 //-----------------------------------------------------------------------------------------------------------------
14807 
14808 char* txDemangle (const char* mangledName, std::nomeow_t)
14809  {
14810 $1 if (!mangledName) return NULL;
14811 
14812 $ char* typeName = NULL;
14813 
14814  #if defined (_GCC_VER)
14815 
14816 $ int err = 1;
14817 $ typeName = ::abi::__cxa_demangle (mangledName, 0, 0, &err); (void) err;
14818  if (typeName) {$ return typeName; }
14819 
14820  #endif
14821 
14822 $ unsigned short flags = 0;
14823 
14824 $ if (mangledName[0] == '.')
14825  {
14826 $ mangledName++;
14827 $ flags = 0x2800; // UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY
14828  }
14829 
14830 $ typeName = _TX_CALL (Win32::__unDName, (NULL, mangledName, 0, malloc, free, flags));
14831  if (typeName) {$ return typeName; }
14832 
14833 $ return _strdup (mangledName);
14834  }
14835 
14836 //-----------------------------------------------------------------------------------------------------------------
14837 
14838 std::string txDemangle (const char* mangledName)
14839  {
14840 $1 char* typeName = txDemangle (mangledName, std::nomeow);
14841 $ std::string name (typeName? typeName : "");
14842 $ free (typeName);
14843 
14844 $ return name;
14845  }
14846 
14847 //-----------------------------------------------------------------------------------------------------------------
14848 
14849 double txQueryPerformance()
14850  {
14851 $1 int maxTime = 500;
14852 $ int maxSamples = 100;
14853 $ POINT size = {100, 100};
14854 
14855 $ HDC dc = _txBuffer_Create (txWindow(), &size, NULL);
14856 $ assert (dc); if (!dc) return -1; //-V547
14857 
14858 $ DWORD mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), 1); //-V202
14859 $ assert (mask);
14860 
14861 $ LARGE_INTEGER freq = {};
14862 $ QueryPerformanceFrequency (&freq) asserted;
14863 
14864 $ LARGE_INTEGER start = {};
14865 $ QueryPerformanceCounter (&start) asserted;
14866 
14867 $ int samples = 0;
14868 $ while (samples++ < maxSamples)
14869  {
14870 $ LARGE_INTEGER cur = {};
14871 $ QueryPerformanceCounter (&cur) asserted;
14872 
14873 $ double t = 1000.0 * (double) (cur.QuadPart - start.QuadPart) / (double) freq.QuadPart;
14874 $ if (t > maxTime) break;
14875 
14876  // Draw test scene
14877 
14878 $ for (int y = 0; y < size.y; y++)
14879  for (int x = 0; x < size.x; x++) txSetPixel (x, y, TX_BLACK, dc);
14880 
14881 $ for (int y = 0; y < size.y; y += 10)
14882  for (int x = 0; x < size.x; x += 50) txTextOut (x, y, "*", dc);
14883 
14884 $ txEllipse (0, 0, size.x, size.y, dc);
14885 $ txFloodFill (size.x/2.0, size.y/2.0, TX_TRANSPARENT, FLOODFILLSURFACE, dc);
14886 
14887 $ txBitBlt (dc, size.x/2.0, 0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted;
14888 $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, size.y/2.0) asserted;
14889 $ txBitBlt (dc, 0, size.y/2.0, size.x/2.0, size.y/2.0, dc, 0, 0) asserted;
14890 $ txBitBlt (dc, size.x/2.0, size.y/2.0, size.x/2.0, size.y/2.0, dc, size.x/2.0, 0) asserted;
14891  }
14892 
14893 $ mask = (DWORD) SetThreadAffinityMask (GetCurrentThread(), mask); //-V106 //-V202
14894 $ assert (mask);
14895 
14896 $ _txBuffer_Delete (&dc);
14897 
14898 $ return 3.0 * samples / sqrt (1.0 * size.x * size.y);
14899  }
14900 
14901 //-----------------------------------------------------------------------------------------------------------------
14902 
14903 unsigned txExtractColor (COLORREF color, COLORREF component)
14904  {
14905 $1 switch (component)
14906  {
14907  case TX_RED:
14908  case TX_HUE: $ return (color >> 0) & 0xFF;
14909 
14910  case TX_GREEN:
14911  case TX_SATURATION: $ return (color >> 8) & 0xFF;
14912 
14913  case TX_BLUE:
14914  case TX_LIGHTNESS: $ return (color >> 16) & 0xFF;
14915 
14916  default: $ return CLR_INVALID;
14917  }
14918  }
14919 
14920 //-----------------------------------------------------------------------------------------------------------------
14921 
14922 COLORREF txRGB2HSL (COLORREF rgbColor)
14923  {
14924 $1 struct xRGB
14925  {
14926  static bool zero (double val)
14927  {
14928  const double prec = 0.001;
14929 
14930  return (fabs (val) < prec);
14931  }
14932  };
14933 
14934 $ double r = txExtractColor (rgbColor, TX_RED) / 255.0, //-V2551
14935  g = txExtractColor (rgbColor, TX_GREEN) / 255.0, //-V2551
14936  b = txExtractColor (rgbColor, TX_BLUE) / 255.0, //-V2551
14937 
14938  m1 = MAX (MAX (r, g), b),
14939  m2 = MIN (MIN (r, g), b),
14940  dm = m1 - m2,
14941  sm = m1 + m2,
14942 
14943  h = 0,
14944  s = 0,
14945  l = sm / 2;
14946 
14947 $ if (!xRGB::zero (dm))
14948  {
14949 $ sm = (sm <= 1)? sm : (2-sm);
14950 $ s = (!xRGB::zero (sm))? dm/sm : 0;
14951 
14952 $ double cr = (!xRGB::zero (dm))? (m1 - r) / dm : 0,
14953  cg = (!xRGB::zero (dm))? (m1 - g) / dm : 0,
14954  cb = (!xRGB::zero (dm))? (m1 - b) / dm : 0;
14955 
14956 $ if (xRGB::zero (r - m1)) h = cb - cg;
14957 $ if (xRGB::zero (g - m1)) h = 2 + cr - cb;
14958 $ if (xRGB::zero (b - m1)) h = 4 + cg - cr;
14959  }
14960 
14961 $ h = (h >= 0)? h*60 : h*60 + 360;
14962 
14963 $ return RGB (ROUND (h / 360.0 * 256), ROUND (s * 255), ROUND (l * 255));
14964  }
14965 
14966 //-----------------------------------------------------------------------------------------------------------------
14967 
14968 COLORREF txHSL2RGB (COLORREF hslColor)
14969  {
14970 $1 struct xRGB
14971  {
14972  static double calc (double h, double m1, double m2)
14973  {
14974 $2 while (h < 0) h += 360;
14975 $ while (h > 360) h -= 360;
14976 
14977 $ return (h < 60)? m1 + (m2-m1) * h / 60 :
14978  (h < 180)? m2 :
14979  (h < 240)? m1 + (m2-m1) * (240-h) / 60 :
14980  m1;
14981  }
14982  };
14983 
14984 $ int si = txExtractColor (hslColor, TX_SATURATION);
14985 
14986 $ double h = txExtractColor (hslColor, TX_HUE) / 256.0 * 360,
14987  s = txExtractColor (hslColor, TX_SATURATION) / 255.0,
14988  l = txExtractColor (hslColor, TX_LIGHTNESS) / 255.0,
14989 
14990  m2 = (l <= 0.5)? l * (1 + s) : l + s - l * s,
14991  m1 = 2 * l - m2,
14992 
14993  r = (si)? xRGB::calc (h + 120, m1, m2) : l,
14994  g = (si)? xRGB::calc (h, m1, m2) : l,
14995  b = (si)? xRGB::calc (h - 120, m1, m2) : l;
14996 
14997 $ return RGB (ROUND (r * 255), ROUND (g * 255), ROUND (b * 255));
14998  }
14999 
15000 //-----------------------------------------------------------------------------------------------------------------
15001 
15002 void tx_fpreset()
15003  {
15004 $1 txAutoLock _lock;
15005 
15006 $ Win32::_fpreset();
15007 
15008 $ unsigned new87 = 0x0008001C; // _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW
15009 
15010  #if !defined (__CYGWIN__)
15011 
15012 $ unsigned old87 = 0;
15013 $ if (_controlfp_s (&old87, 0, 0) == 0)
15014  {$ (void) _controlfp_s (&old87, old87 & ~new87, 0x0008001F); } // _MCW_EM
15015 
15016  #else
15017 
15018 $ Win32::_controlfp (Win32::_controlfp (0, 0) & ~new87, 0x0008001F); // _MCW_EM
15019 
15020  #endif
15021  }
15022 
15023 #endif // TX_COMPILED
15024 
15025 //-----------------------------------------------------------------------------------------------------------------
15026 
15027 #if defined (_TX_CPP11)
15028 template <int txFramesToAverage>
15029 #endif
15030 
15031 double txGetFPS (int minFrames)
15032  {
15033 $1 static _tx_thread LARGE_INTEGER time0 = {}; if (!time0.QuadPart) QueryPerformanceCounter (&time0);
15034 $ LARGE_INTEGER time = {}; QueryPerformanceCounter (&time);
15035 
15036 $ if (time.QuadPart - time0.QuadPart == 0)
15037  {$ return 0; }
15038 
15039 $ LARGE_INTEGER freq = {}; QueryPerformanceFrequency (&freq);
15040 
15041 $ double fps = (double) freq.QuadPart / (double) (time.QuadPart - time0.QuadPart);
15042 $ time0 = time;
15043 
15044 $ if (txFramesToAverage == 0) return fps;
15045 
15046 $ static _tx_thread double average [txFramesToAverage] = {};
15047 $ static _tx_thread unsigned n = 0;
15048 
15049 $ average [n++ % txFramesToAverage] = fps;
15050 
15051 $ unsigned nn = MIN (n, (unsigned) sizearr (average));
15052 
15053 $ fps = 0;
15054 $ for (unsigned i = 0; i < nn; i++) fps += average[i];
15055 $ fps /= nn;
15056 
15057 $ return ((int)n >= MIN (minFrames, txFramesToAverage))? fps : 0;
15058  }
15059 
15060 //-----------------------------------------------------------------------------------------------------------------
15061 
15062 template <typename T>
15063 inline T zero() { T __zero = {}; return __zero; }
15064 
15065 //-----------------------------------------------------------------------------------------------------------------
15066 
15067 inline double random (std::nomeow_t, double left, double right)
15068  {
15069  return left + (right - left) * ((double) rand() / RAND_MAX);
15070  }
15071 
15072 //-----------------------------------------------------------------------------------------------------------------
15073 
15074 template <typename Tx, typename Ta, typename Tb>
15075 inline bool In (std::nomeow_t, Tx x, Ta a, Tb b)
15076  {
15077  return a <= x && x <= b;
15078  }
15079 
15080 //-----------------------------------------------------------------------------------------------------------------
15081 
15082 inline bool In (std::nomeow_t, const POINT& pt, const RECT& rect)
15083  {
15084  if (_TX_ARGUMENT_FAILED (&pt)) return false;
15085  if (_TX_ARGUMENT_FAILED (&rect)) return false;
15086 
15087  return In (std::nomeow, pt.x, rect.left, rect.right) &&
15088  In (std::nomeow, pt.y, rect.top, rect.bottom);
15089  }
15090 
15091 //-----------------------------------------------------------------------------------------------------------------
15092 
15093 inline bool In (std::nomeow_t, const COORD& pt, const SMALL_RECT& rect)
15094  {
15095  if (_TX_ARGUMENT_FAILED (&pt)) return false;
15096  if (_TX_ARGUMENT_FAILED (&rect)) return false;
15097 
15098  return In (std::nomeow, pt.X, rect.Left, rect.Right) &&
15099  In (std::nomeow, pt.Y, rect.Top, rect.Bottom);
15100  }
15101 
15102 //-----------------------------------------------------------------------------------------------------------------
15103 
15104 inline int random (int range)
15105  {
15106  if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206
15107 
15108  return rand() % range;
15109  }
15110 
15111 //-----------------------------------------------------------------------------------------------------------------
15112 
15113 inline double random (double left, double right)
15114  {
15115  if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206
15116 
15117  return random (std::nomeow, left, right);
15118  }
15119 
15120 //-----------------------------------------------------------------------------------------------------------------
15121 
15122 template <typename Tx, typename Ta, typename Tb>
15123 inline bool In (Tx x, Ta a, Tb b)
15124  {
15125  if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206
15126 
15127  return In (std::nomeow, x, a, b);
15128  }
15129 
15130 //-----------------------------------------------------------------------------------------------------------------
15131 
15132 inline bool In (const POINT& pt, const RECT& rect)
15133  {
15134  if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206
15135 
15136  return In (std::nomeow, pt, rect);
15137  }
15138 
15139 //-----------------------------------------------------------------------------------------------------------------
15140 
15141 inline bool In (const COORD& pt, const SMALL_RECT& rect)
15142  {
15143  if (rand() % 100 == 0) fprintf (stderr, "%.4s ", (const volatile char*) ((rand() & 0x0F)? &_txCanaryFirst : &_txCanaryLast)); //-V206
15144 
15145  return In (std::nomeow, pt, rect);
15146  }
15147 
15148 //}
15149 //=================================================================================================================
15150 
15151 //=================================================================================================================
15152 //{ txPrintf() implementation
15153 // Реализация txPrintf()
15154 //=================================================================================================================
15155 
15156 #if defined (_TX_CPP11)
15157 
15158 template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args);
15159 template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args);
15160 template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args);
15161 template <typename T, typename... ArgsT> void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args);
15162  void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt);
15163 
15164 template <typename T> void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg);
15165  void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg);
15166  void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt);
15167 
15168 //-----------------------------------------------------------------------------------------------------------------
15169 
15170 template <typename T, typename... ArgsT>
15171 void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg, ArgsT... args)
15172  {
15173 $1 assert (fmt);
15174 
15175 $ _txPrintV (stream, format, n, fmt);
15176 
15177  if (fmt[0] == '%') {$}
15178  else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); }
15179 
15180 $ _txPrintV (stream, format, n, fmt, arg);
15181 
15182 $ _txPrintF (stream, format, n+1, fmt, args...);
15183  }
15184 
15185 //-----------------------------------------------------------------------------------------------------------------
15186 
15187 template <typename T, typename... ArgsT>
15188 void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, const T& arg, ArgsT... args)
15189  {
15190 $1 assert (&stream);
15191 $ assert (fmt);
15192 
15193 $ _txPrintV (stream, format, n, fmt);
15194 
15195  if (fmt[0] == '%' && fmt[1] == '*') {$ stream << std::setw (width); } //-V2006
15196  else {$ TX_ERROR ("\"%%*\" required to setwidth (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, fmt, txTypename (arg), n, format); }
15197 
15198 $ _txPrintV (stream, format, n, fmt, arg);
15199 
15200 $ _txPrintF (stream, format, n+1, fmt, args...);
15201  }
15202 
15203 //-----------------------------------------------------------------------------------------------------------------
15204 
15205 template <typename T, typename... ArgsT>
15206 void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, precision_t prec, const T& arg, ArgsT... args)
15207  {
15208 $1 assert (&stream);
15209 $ assert (fmt);
15210 
15211 $ _txPrintV (stream, format, n, fmt);
15212 
15213  if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*') {$ stream << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028
15214  else {$ TX_ERROR ("\"%%.*\" required to setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", prec, fmt, txTypename (arg), n, format); }
15215 
15216 $ _txPrintV (stream, format, n, fmt, arg);
15217 
15218 $ _txPrintF (stream, format, n+1, fmt, args...);
15219  }
15220 
15221 //-----------------------------------------------------------------------------------------------------------------
15222 
15223 template <typename T, typename... ArgsT>
15224 void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt, width_t width, precision_t prec, const T& arg, ArgsT... args)
15225  {
15226 $1 assert (&stream);
15227 $ assert (fmt);
15228 
15229 $ _txPrintV (stream, format, n, fmt);
15230 
15231  if (fmt[0] == '%' && fmt[1] == '*' && fmt[2] == '.' && fmt[3] == '*') {$ stream << std::setw (width) << std::setprecision ((std::streamsize) (prec + 1)); } //-V2006 //-V1028
15232  else {$ TX_ERROR ("\"%%*.*\" required to setwidth (%d) and setprecision (%d) in ...\"%s\" while printing %s argument %d in \"%s\"", width, prec, fmt, txTypename (arg), n, format); }
15233 
15234 $ _txPrintV (stream, format, n, fmt, arg);
15235 
15236 $ _txPrintF (stream, format, n+1, fmt, args...);
15237  }
15238 
15239 //-----------------------------------------------------------------------------------------------------------------
15240 
15241 inline void _txPrintF (std::ostringstream& stream, const char* format, int n, const char*& fmt)
15242  {
15243 $1 assert (fmt);
15244 
15245 $ _txPrintV (stream, format, n, fmt);
15246 
15247  if (!fmt[0]) {$}
15248  else {$ TX_ERROR ("No argument provided for %% in \"%s\" while printing \"%s\"", fmt, format); }
15249  }
15250 
15251 //-----------------------------------------------------------------------------------------------------------------
15252 
15253 inline void _txPrintV (std::ostringstream& stream, const char*, int, const char*& fmt)
15254  {
15255 $1 assert (&stream);
15256 $ assert (fmt);
15257 
15258 $ while (*fmt)
15259  {
15260  if (fmt[0] == '%')
15261  {
15262  if (fmt[1] == '%') fmt++;
15263  else break;
15264  }
15265 
15266  stream << *fmt++;
15267  }
15268 $ }
15269 
15270 //-----------------------------------------------------------------------------------------------------------------
15271 
15272 template <typename T>
15273 void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, const T& arg)
15274  {
15275 $1 assert (&stream);
15276 $ assert (fmt);
15277 
15278 $ if (_TX_ARGUMENT_FAILED (&arg)) return;
15279 
15280  if (fmt[0] == '%') {$}
15281  else {$ TX_ERROR ("\"%%$\" required to print an argument in ...\"%s\" while printing %s argument %d in \"%s\"", fmt, txTypename (arg), n, format); }
15282 
15283 $ fmt++;
15284 
15285 $ char oldFill = stream.fill (' ');
15286 $ std::ios_base::fmtflags oldFlags = stream.flags();
15287 
15288 $ for (;;) switch (*fmt)
15289  {
15290  case '-': $ stream << std::left; fmt++; break;
15291  case '+': $ stream << std::showpos; fmt++; break;
15292  case ' ': $ stream.fill (' '); fmt++; break;
15293  case '#': $ stream << std::showbase; fmt++; break;
15294  case '0': $ stream.fill ('0'); fmt++; break;
15295 
15296  default: $ goto end;
15297  }
15298  end:
15299 
15300 $ int width = (*fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0);
15301 $ int prec = (*fmt == '.')? (*++fmt != '*')? (int) strtoul (fmt, const_cast <char**> (&fmt), 10) : (fmt++, 0) : 0;
15302 
15303  if (width) {$ stream << std::setw (width); }
15304  if (prec) {$ stream << std::setprecision (prec); }
15305 
15306 $ fmt += strspn (fmt, "hljztL");
15307 
15308 $ switch (*fmt)
15309  {
15310  case '$':
15311  case '?': $ break;
15312 
15313  case 'd':
15314  case 'i':
15315  case 'u': $ stream << std::dec; break;
15316 
15317  case 'o': $ stream << std::oct; break;
15318 
15319  case 'x': $ stream << std::hex; break;
15320  case 'X': $ stream << std::hex << std::uppercase; break;
15321 
15322  case 'f': $ stream << std::fixed; break;
15323  case 'F': $ stream << std::fixed << std::uppercase; break;
15324 
15325  case 'e': $ stream << std::scientific; break;
15326  case 'E': $ stream << std::scientific << std::uppercase; break;
15327 
15328  case 'g': $ break;
15329  case 'G': $ stream << std::uppercase; break;
15330 
15331  case 'a': $ break;
15332  case 'A': $ stream << std::uppercase; break;
15333 
15334  case 'c':
15335  case 's':
15336  case 'p': $ break;
15337 
15338  default: $ TX_ERROR ("Invalid format '%.1s' at \"%s\" while printing %s argument %d in \"%s\"", fmt, fmt, txTypename (arg), n, format); break;
15339  }
15340 
15341 $ fmt++;
15342 
15343  if (&arg) {$ stream << arg; }
15344  else {$ stream << "(null)"; }
15345 
15346 $ stream.fill (oldFill);
15347 $ stream.flags (oldFlags);
15348  }
15349 
15350 //-----------------------------------------------------------------------------------------------------------------
15351 
15352 inline void _txPrintV (std::ostringstream& stream, const char* format, int n, const char*& fmt, int* arg) //-V2009
15353  {
15354 $1 assert (fmt);
15355 
15356  if (_TX_ARGUMENT_FAILED (arg)) return;
15357 
15358  if (fmt[0] == '%' && fmt[1] == 'n') {$}
15359  else {$ TX_ERROR ("\"%%n\" required to store print length in int* argument %d in \"%s\"", n, format); }
15360 
15361 $ *arg = (int) stream.str().length(); //-V202
15362 
15363 $ fmt += 2;
15364  }
15365 
15366 //-----------------------------------------------------------------------------------------------------------------
15367 
15368 template <typename T> inline const T& _txPrintfNormalizeArg (const T& arg) { if (_TX_ARGUMENT_FAILED (&arg)) {;} return arg; }
15369  inline const char* _txPrintfNormalizeArg (const std::string& arg) { if (_TX_ARGUMENT_FAILED (&arg)) return NULL; return arg.c_str(); }
15370 
15371 //-----------------------------------------------------------------------------------------------------------------
15372 
15373 template <typename... ArgsT>
15374 inline int txPrintf (std::ostringstream& stream, const char* format, ArgsT... args)
15375  {
15376 $1 if (_TX_ARGUMENT_FAILED (&stream)) return 0;
15377 $ if (_TX_ARGUMENT_FAILED (&format)) return 0;
15378 
15379 $ const char* fmt = format;
15380 $ _txPrintF (stream, format, 2, fmt, _txPrintfNormalizeArg (args)...);
15381 
15382 $ return (int) stream.str().length(); //-V202
15383  }
15384 
15385 //-----------------------------------------------------------------------------------------------------------------
15386 
15387 template <typename... ArgsT>
15388 inline int txPrintf (char buffer[], size_t size, const char* format, ArgsT... args)
15389  {
15390 $1 if (_TX_ARGUMENT_FAILED (&buffer)) return 0;
15391 $ if (_TX_ARGUMENT_FAILED (&format)) return 0;
15392 
15393 $ if (size > 0) size--;
15394 $ buffer[size] = 0;
15395 
15396 $ if (!size) return 0;
15397 
15398 $ std::ostringstream stream;
15399 $ stream.rdbuf() -> pubsetbuf (buffer, size);
15400 
15401 $ txPrintf (stream, format, args...);
15402 
15403 $ return (int) stream.str().length(); //-V202
15404  }
15405 
15406 //-----------------------------------------------------------------------------------------------------------------
15407 
15408 template <typename... ArgsT>
15409 inline std::string txFormat (const char* format, ArgsT... args)
15410  {
15411 $1 if (_TX_ARGUMENT_FAILED (&format)) return "";
15412 
15413 $ std::ostringstream stream;
15414 
15415 $ txPrintf (stream, format, args...);
15416 
15417 $ return stream.str();
15418  }
15419 
15420 //-----------------------------------------------------------------------------------------------------------------
15421 
15422 template <typename... ArgsT>
15423 inline int txPrintf (const char* format, ArgsT... args)
15424  {
15425 $1 if (_TX_ARGUMENT_FAILED (&format)) return 0;
15426 
15427 $ return printf ("%s", txFormat (format, args...) .c_str());
15428  }
15429 
15430 #endif
15431 
15432 //-----------------------------------------------------------------------------------------------------------------
15433 
15434  int _txPrintfCheck (const char* format, ...) tx_printfy (1);
15435 inline int _txPrintfCheck (const char*, ...) { return 0; }
15436 
15437 //}
15438 //=================================================================================================================
15439 
15440 //=================================================================================================================
15441 //{ txDialog methods implementation
15442 // Реализация методов класса txDialog
15443 //
15444 // See [1] http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms645389%28v=vs.85%29.aspx
15445 // [2] http://blogs.msdn.microsoft.com/oldnewthing/20050429-00/?p=35743
15446 // [3] http://blogs.msdn.microsoft.com/oldnewthing/20040623-00/?p=38753
15447 //=================================================================================================================
15448 
15449 #ifndef TX_COMPILED // <<< THE CODE IS HERE, UNFOLD IT <<<
15450 
15451 txDialog::txDialog () :
15452  layout_ (NULL)
15453  {$1}
15454 
15455 //-----------------------------------------------------------------------------------------------------------------
15456 
15457 txDialog::txDialog (const Layout* layout) :
15458  layout_ (layout)
15459  {$1}
15460 
15461 //-----------------------------------------------------------------------------------------------------------------
15462 
15463 const txDialog::Layout* txDialog::setLayout (const Layout* layout)
15464  {
15465 $1 assert (layout);
15466 
15467 $ return ::std::swap (layout_, layout), layout;
15468  }
15469 
15470 //-----------------------------------------------------------------------------------------------------------------
15471 
15472 intptr_t txDialog::dialogBox (WORD resourceID)
15473  {
15474 $1 const char* resName = (char*)(uintptr_t) resourceID;
15475 
15476 $ if (!FindResource (NULL, resName, RT_DIALOG)) return TX_DEBUG_ERROR ("Не найден ресурс диалога %d", resourceID), 0;
15477 
15478 $ return DialogBoxParam (NULL, resName, NULL, (DLGPROC) DialogProc_, (LPARAM) this);
15479  }
15480 
15481 //-----------------------------------------------------------------------------------------------------------------
15482 
15483 intptr_t txDialog::dialogBox (const txDialog::Layout* layout /*= NULL*/, size_t bufsize /*= 0*/)
15484  {
15485 $1 if (!layout) layout = layout_;
15486 $ if (!layout) return TX_DEBUG_ERROR ("Не установлен динамический шаблон диалога), 0; $ if (!bufsize) bufsize = 1024; $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize); $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога"), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки), 0;
15487 
15488 $ if (!bufsize) bufsize = 1024;
15489 
15490 $ DLGTEMPLATE* tmpl = (DLGTEMPLATE*) GlobalAlloc (GPTR, bufsize);
15491 $ if (!tmpl) return TX_DEBUG_ERROR ("GlobalAlloc(): Нет памяти для шаблона диалога), 0; $ const Layout* dlg = &layout[0]; $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 }; $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize, (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0, dlg->x, dlg->y, dlg->sx, dlg->sy, dlg->caption? dlg->caption : def.caption, dlg->font? dlg->font : def.font, dlg->fontsize? dlg->fontsize : def.fontsize, NULL); $ WORD i = 0; $ for (i = 1; layout[i].wndclass != END; ++i) { $ const Layout* item = &layout[i]; $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl), item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy, item->id, (const char*)(uintptr_t) item->wndclass, item->caption); } $ tmpl->cdit = (unsigned short) (i-1); $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this); $ GlobalFree (tmpl); $ return res; } //----------------------------------------------------------------------------------------------------------------- int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM) { $1 switch (msg) { case WM_INITDIALOG: $ SetForegroundWindow (wnd); $ break; case WM_COMMAND: $ switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow()); $ EndDialog (wnd, (uintptr_t) this); $ break; default: $ break; } $ break; default: $ break; } $ return FALSE; } //----------------------------------------------------------------------------------------------------------------- intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { $1 static txDialog* this__ = NULL; $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam; $ if (!this__) return FALSE; $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109 } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle, WORD controls, short x, short y, short cx, short cy, const char caption[], const char font[], WORD fontsize, const char menu[]) { $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL; $ WORD* pw = (WORD*) globalMem; $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->cdit = controls; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ if (menu > (const char*) 0xFFFF) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } else { $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0); $ *pw++ = (WORD)(uintptr_t) menu; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547 (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ if (style & DS_SETFONT) { $ *pw++ = fontsize; $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202 } $ return pw; } //----------------------------------------------------------------------------------------------------------------- void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle, short x, short y, short cx, short cy, WORD id, const char wclass[], const char caption[]) { $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL; $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary $ ((ULONG&) pw) += 3; //-V205 $ ((ULONG&) pw) >>= 2; //-V205 $ ((ULONG&) pw) <<= 2; //-V205 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++; $ tmpl->style = style; $ tmpl->dwExtendedStyle = exStyle; $ tmpl->x = x; $ tmpl->y = y; $ tmpl->cx = cx; $ tmpl->cy = cy; $ tmpl->id = id; $ if (HIWORD (wclass) == 0xFFFF) { $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass)); $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass)); } else if (wclass) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ if (caption) { $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw, (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202 } else { $ *pw++ = 0; } $ *pw++ = 0; $ return pw; } #endif // TX_COMPILED //} //================================================================================================================= //================================================================================================================= //{ Cleaning up the utility macros // Очистка служебных макросов //================================================================================================================= #undef $ #undef $0 #undef $1 #undef $2 #undef $3 #undef $4 #undef $5 #undef $6 #undef $7 #undef $8 #undef $9 #undef $$ //} //================================================================================================================= //! @endcond } //================================================================================================================= //{ Experimental Debugging macros //! @name Экспериментальные отладочные макросы //================================================================================================================= //{---------------------------------------------------------------------------------------------------------------- //! @ingroup Misc //! @brief Отладочная печать переменной во время вычисления выражения или участка кода //! во время его выполнения. //! //! Сделай приятными твои <i>круглые сутки), 0;
15492 
15493 $ const Layout* dlg = &layout[0];
15494 $ const Layout def = { DIALOG, NULL, 0, 0,0,0,0, WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_CENTER, "MS Shell Dlg", 8 };
15495 
15496 $ void* ptr = _tx_DLGTEMPLATE_Create (tmpl, bufsize,
15497  (dlg->style? dlg->style : def.style) | DS_SETFONT, 0, 0,
15498  dlg->x, dlg->y, dlg->sx, dlg->sy,
15499  dlg->caption? dlg->caption : def.caption,
15500  dlg->font? dlg->font : def.font,
15501  dlg->fontsize? dlg->fontsize : def.fontsize, NULL);
15502 $ WORD i = 0;
15503 $ for (i = 1; layout[i].wndclass != END; ++i)
15504  {
15505 $ const Layout* item = &layout[i];
15506 
15507 $ ptr = _tx_DLGTEMPLATE_Add (ptr, bufsize - ((char*)ptr - (char*)tmpl),
15508  item->style | WS_VISIBLE, 0, item->x, item->y, item->sx, item->sy,
15509  item->id, (const char*)(uintptr_t) item->wndclass, item->caption);
15510  }
15511 
15512 $ tmpl->cdit = (unsigned short) (i-1);
15513 
15514 $ intptr_t res = DialogBoxIndirectParam (NULL, tmpl, NULL, (DLGPROC) DialogProc_, (LPARAM) this);
15515 
15516 $ GlobalFree (tmpl);
15517 
15518 $ return res;
15519  }
15520 
15521 //-----------------------------------------------------------------------------------------------------------------
15522 
15523 int txDialog::dialogProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM)
15524  {
15525 $1 switch (msg)
15526  {
15527  case WM_INITDIALOG: $ SetForegroundWindow (wnd);
15528  $ break;
15529 
15530  case WM_COMMAND: $ switch (LOWORD (wParam))
15531  {
15532  case IDOK:
15533  case IDCANCEL: $ SetForegroundWindow (txWindow()? txWindow() : Win32::GetConsoleWindow());
15534  $ EndDialog (wnd, (uintptr_t) this);
15535  $ break;
15536 
15537  default: $ break;
15538  }
15539  $ break;
15540  default: $ break;
15541  }
15542 
15543 $ return FALSE;
15544  }
15545 
15546 //-----------------------------------------------------------------------------------------------------------------
15547 
15548 intptr_t CALLBACK txDialog::DialogProc_ (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
15549  {
15550 $1 static txDialog* this__ = NULL;
15551 $ if (msg == WM_INITDIALOG) this__ = (txDialog*) lParam;
15552 $ if (!this__) return FALSE;
15553 
15554 $ return this__-> dialogProc (wnd, msg, wParam, lParam); //-V109
15555  }
15556 
15557 //-----------------------------------------------------------------------------------------------------------------
15558 
15559 void* _tx_DLGTEMPLATE_Create (void* globalMem, size_t bufsize, DWORD style, DWORD exStyle,
15560  WORD controls, short x, short y, short cx, short cy,
15561  const char caption[], const char font[], WORD fontsize, const char menu[])
15562  {
15563 $1 if (_TX_ARGUMENT_FAILED (globalMem)) return NULL;
15564 
15565 $ WORD* pw = (WORD*) globalMem;
15566 
15567 $ DLGTEMPLATE* tmpl = ((DLGTEMPLATE*&) pw)++;
15568 
15569 $ tmpl->style = style;
15570 $ tmpl->dwExtendedStyle = exStyle;
15571 $ tmpl->cdit = controls;
15572 $ tmpl->x = x;
15573 $ tmpl->y = y;
15574 $ tmpl->cx = cx;
15575 $ tmpl->cy = cy;
15576 
15577 $ if (menu > (const char*) 0xFFFF)
15578  {
15579 $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (menu? menu : ""), -1, (wchar_t*) pw, //-V547
15580  (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202
15581  }
15582  else
15583  {
15584 $ *pw++ = (WORD)(uintptr_t) (menu? 0xFFFF : 0);
15585 $ *pw++ = (WORD)(uintptr_t) menu;
15586  }
15587 
15588 $ if (caption)
15589  {
15590 $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (caption? caption : ""), -1, (wchar_t*) pw, //-V547
15591  (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202
15592  }
15593 
15594 $ if (style & DS_SETFONT)
15595  {
15596 $ *pw++ = fontsize;
15597 $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, (font? font : ""), -1, (wchar_t*) pw,
15598  (int) (bufsize? bufsize - ((char*) pw - (char*) globalMem) : 0xFFFF)); //-V202
15599  }
15600 
15601 $ return pw;
15602  }
15603 
15604 //-----------------------------------------------------------------------------------------------------------------
15605 
15606 void* _tx_DLGTEMPLATE_Add (void* dlgTemplatePtr, size_t bufsize, DWORD style, DWORD exStyle,
15607  short x, short y, short cx, short cy,
15608  WORD id, const char wclass[], const char caption[])
15609  {
15610 $1 if (_TX_ARGUMENT_FAILED (dlgTemplatePtr)) return NULL;
15611 
15612 $ WORD* pw = (LPWORD) dlgTemplatePtr; // Force align at word boundary
15613 $ ((ULONG&) pw) += 3; //-V205
15614 $ ((ULONG&) pw) >>= 2; //-V205
15615 $ ((ULONG&) pw) <<= 2; //-V205
15616 
15617 $ DLGITEMTEMPLATE* tmpl = ((DLGITEMTEMPLATE*&) pw)++;
15618 
15619 $ tmpl->style = style;
15620 $ tmpl->dwExtendedStyle = exStyle;
15621 $ tmpl->x = x;
15622 $ tmpl->y = y;
15623 $ tmpl->cx = cx;
15624 $ tmpl->cy = cy;
15625 $ tmpl->id = id;
15626 
15627 $ if (HIWORD (wclass) == 0xFFFF)
15628  {
15629 $ *pw++ = (WORD) (HIWORD ((uintptr_t) wclass));
15630 $ *pw++ = (WORD) (LOWORD ((uintptr_t) wclass));
15631  }
15632  else if (wclass)
15633  {
15634 $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, const_cast <char*> (wclass), -1, (wchar_t*) pw,
15635  (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202
15636  }
15637  else
15638  {
15639 $ *pw++ = 0;
15640  }
15641 
15642 $ if (caption)
15643  {
15644 $ pw += MultiByteToWideChar (_TX_CODEPAGE, 0, caption, -1, (wchar_t*) pw,
15645  (int) (bufsize? bufsize - ((char*) pw - (char*) dlgTemplatePtr) : 0xFFFF)); //-V202
15646  }
15647  else
15648  {
15649 $ *pw++ = 0;
15650  }
15651 
15652 $ *pw++ = 0;
15653 
15654 $ return pw;
15655  }
15656 
15657 #endif // TX_COMPILED
15658 
15659 //}
15660 //=================================================================================================================
15661 
15662 //=================================================================================================================
15663 //{ Cleaning up the utility macros
15664 // Очистка служебных макросов
15665 //=================================================================================================================
15666 
15667 #undef $
15668 #undef $0
15669 #undef $1
15670 #undef $2
15671 #undef $3
15672 #undef $4
15673 #undef $5
15674 #undef $6
15675 #undef $7
15676 #undef $8
15677 #undef $9
15678 #undef $$
15679 
15680 //}
15681 //=================================================================================================================
15682 
15684 
15685 //=================================================================================================================
15686 //{ Experimental Debugging macros
15688 //=================================================================================================================
15689 
15690 //{----------------------------------------------------------------------------------------------------------------
15810 //}----------------------------------------------------------------------------------------------------------------
15811 
15812 #ifndef __TX_DEBUG_MACROS
15813 #define __TX_DEBUG_MACROS ("Группа отладочных $-макросов")
15814 
15816 //-----------------------------------------------------------------------------------------------------------------
15817 
15818 #define $H txSetConsoleAttr (FOREGROUND_BLACK | BACKGROUND_BLACK);
15819 #define $B txSetConsoleAttr (FOREGROUND_BLUE | BACKGROUND_BLACK);
15820 #define $G txSetConsoleAttr (FOREGROUND_GREEN | BACKGROUND_BLACK);
15821 #define $C txSetConsoleAttr (FOREGROUND_CYAN | BACKGROUND_BLACK);
15822 #define $R txSetConsoleAttr (FOREGROUND_RED | BACKGROUND_BLACK);
15823 #define $M txSetConsoleAttr (FOREGROUND_MAGENTA | BACKGROUND_BLACK);
15824 #define $Y txSetConsoleAttr (FOREGROUND_DARKYELLOW | BACKGROUND_BLACK);
15825 #define $d txSetConsoleAttr (FOREGROUND_LIGHTGRAY | BACKGROUND_BLACK);
15826 #define $D txSetConsoleAttr (FOREGROUND_DARKGRAY | BACKGROUND_BLACK);
15827 #define $b txSetConsoleAttr (FOREGROUND_LIGHTBLUE | BACKGROUND_BLACK);
15828 #define $g txSetConsoleAttr (FOREGROUND_LIGHTGREEN | BACKGROUND_BLACK);
15829 #define $c txSetConsoleAttr (FOREGROUND_LIGHTCYAN | BACKGROUND_BLACK);
15830 #define $r txSetConsoleAttr (FOREGROUND_LIGHTRED | BACKGROUND_BLACK);
15831 #define $m txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA | BACKGROUND_BLACK);
15832 #define $y txSetConsoleAttr (FOREGROUND_YELLOW | BACKGROUND_BLACK);
15833 #define $h txSetConsoleAttr (FOREGROUND_WHITE | BACKGROUND_BLACK);
15834 
15835 #define $i txSetConsoleAttr (FOREGROUND_LIGHTCYAN | BACKGROUND_BLUE);
15836 #define $I txSetConsoleAttr (FOREGROUND_YELLOW | BACKGROUND_BLUE);
15837 #define $o txSetConsoleAttr (FOREGROUND_WHITE | BACKGROUND_GREEN);
15838 #define $O txSetConsoleAttr (FOREGROUND_YELLOW | BACKGROUND_GREEN);
15839 #define $e txSetConsoleAttr (FOREGROUND_WHITE | BACKGROUND_RED);
15840 #define $E txSetConsoleAttr (FOREGROUND_YELLOW | BACKGROUND_RED);
15841 #define $w txSetConsoleAttr (FOREGROUND_LIGHTMAGENTA | BACKGROUND_MAGENTA);
15842 #define $W txSetConsoleAttr (FOREGROUND_YELLOW | BACKGROUND_MAGENTA);
15843 #define $f txSetConsoleAttr (FOREGROUND_BLACK | BACKGROUND_LIGHTRED);
15844 #define $F txSetConsoleAttr (FOREGROUND_MAGENTA | BACKGROUND_LIGHTRED);
15845 #define $l txSetConsoleAttr (FOREGROUND_BLACK | BACKGROUND_DARKGRAY);
15846 #define $L txSetConsoleAttr (FOREGROUND_LIGHTGRAY | BACKGROUND_DARKGRAY);
15847 
15848 #define $T( cond ) txSetConsoleAttr ((cond)? FOREGROUND_LIGHTGREEN : FOREGROUND_LIGHTRED );
15849 
15850 #define $s _txSaveConsoleAttr TX_JOIN (__txSavedConsoleAttrs, __LINE__);
15851 
15852 #define $sH $s $H
15853 #define $sB $s $B
15854 #define $sG $s $G
15855 #define $sC $s $C
15856 #define $sR $s $R
15857 #define $sM $s $M
15858 #define $sY $s $Y
15859 #define $sd $s $d
15860 #define $sD $s $D
15861 #define $sb $s $b
15862 #define $sg $s $g
15863 #define $sc $s $c
15864 #define $sr $s $r
15865 #define $sm $s $m
15866 #define $sy $s $y
15867 #define $sh $s $h
15868 
15869 #define $si $s $i
15870 #define $sI $s $I
15871 #define $so $s $o
15872 #define $sO $s $O
15873 #define $se $s $e
15874 #define $sE $s $E
15875 #define $sw $s $w
15876 #define $sW $s $W
15877 #define $sf $s $f
15878 #define $sF $s $F
15879 #define $sl $s $l
15880 #define $sL $s $L
15881 
15882 #define $sT( cond ) $s $T (cond)
15883 
15884 #define $test(cond) { if (!!(cond)) { $o std::cerr << "[PASSED] " __TX_FILELINE__ ": " #cond; } \
15885  else { $e std::cerr << "[FAILED] " __TX_FILELINE__ ": " #cond; } $d; }
15886 
15887 #define $status(cond) $test (cond)
15888 
15889 #define $unittest( code, expected ) \
15890  { \
15891  const _tx_decltype (code) & _result = (code); /* Should use auto, but g++ 4.7.2 default std is < 2011 */ \
15892  const _tx_decltype (expected) & _expected = (expected); \
15893  \
15894  if (_result == _expected) \
15895  { $so std::cerr << "[PASSED] " __TX_FILELINE__ ": " #code; } \
15896  else \
15897  { $se std::cerr << "[FAILED] " __TX_FILELINE__ ": " #code " == (" << _result << "), should be (" << _expected << ")"; } \
15898  \
15899  $n; \
15900  (_result == _expected); \
15901  }
15902 
15903 //=================================================================================================================
15904 
15905 #define $V( var, ...) ( _txDumpVar ((var), _tx$PrefixV ( __VA_ARGS__), "]\n") )
15906 #define $V_( var, ...) ( _txDumpVar ((var), _tx$PrefixV ( __VA_ARGS__), "] " ) )
15907 #define $V__(var, ...) ( _txDumpVar ((var), _tx$PrefixV ( __VA_ARGS__), "]" ) )
15908 
15909 #define $( var, ...) ( _txDumpVar ((var), _tx$Prefix (#var, __VA_ARGS__), "]\n") )
15910 #define $_( var, ...) ( _txDumpVar ((var), _tx$Prefix (#var, __VA_ARGS__), "] " ) )
15911 #define $__( var, ...) ( _txDumpVar ((var), _tx$Prefix (#var, __VA_ARGS__), "]" ) )
15912 
15913 #define $x( var, ...) ( _txDumpVar ((var), _tx$Prefix (#var, __VA_ARGS__), "]\n", ::std::ios_base::showbase | ::std::ios_base::hex) )
15914 #define $x_( var, ...) ( _txDumpVar ((var), _tx$Prefix (#var, __VA_ARGS__), "] ", ::std::ios_base::showbase | ::std::ios_base::hex) )
15915 
15916 #define $v( var, cond, ...) { { $st (cond); _txDumpVar ((var), _tx$Prefix (#var, __VA_ARGS__), "]" ); } $n; }
15917 #define $v_( var, cond, ...) { $st (cond); _txDumpVar ((var), _tx$Prefix (#var, __VA_ARGS__), "]" ); }
15918 
15919 #define $$ { txOutputDebugPrintf ("\f\n"); { $sC txOutputDebugPrintf ("\f" "[%s:%d %s]", __FILE__, __LINE__, __TX_FUNCTION__); } txOutputDebugPrintf ("\f\n"); }
15920 #define $$_ { txOutputDebugPrintf ("\f\n"); { $sC txOutputDebugPrintf ("\f" "[" "%d %s]", __LINE__, __func__); } txOutputDebugPrintf ("\f\n"); }
15921 #define $meow(...) { txOutputDebugPrintf ("\f\n"); { $sc txOutputDebugPrintf ("\f" "[%s:%d %s]", __FILE__, __LINE__, __func__); txOutputDebugPrintf ("\f " __VA_ARGS__); } txOutputDebugPrintf ("\f\n"); }
15922 
15923 #define $$$( ... ) ( ::std::cerr << "\n[" __TX_FILELINE__ ": " #__VA_ARGS__ "]\n", _txDumpVar ((__VA_ARGS__),"\n[" __TX_FILELINE__ ": " #__VA_ARGS__ ": ", ", DONE]\n\n") )
15924 #define $$$_( ... ) ( ::std::cerr << "\n[" __TX_FILELINE__ ": " #__VA_ARGS__ "]\n", _txDumpVar ((__VA_ARGS__), "[" __TX_FILELINE__ ": " #__VA_ARGS__ ": ", ", DONE]\n\n") )
15925 
15926 #define $$$$( ... ) { ::std::cerr << "\n[" __TX_FILELINE__ ": " #__VA_ARGS__ "]\n"; _txDumpVarSuffix ("\n[" __TX_FILELINE__ ": " #__VA_ARGS__ " DONE]\n\n"); { __VA_ARGS__; } }
15927 #define $$$$_( ... ) { ::std::cerr << "\n[" __TX_FILELINE__ ": " #__VA_ARGS__ "]\n"; _txDumpVarSuffix ( "[" __TX_FILELINE__ ": " #__VA_ARGS__ " DONE]\n\n"); { __VA_ARGS__; } }
15928 #define $do( ... ) ::std::cerr << "\n[" __TX_FILELINE__ ": " #__VA_ARGS__ "]\n"; __VA_ARGS__
15929 #define $DO( ... ) ::std::cerr << "\n[" __TX_FILELINE__ ": " #__VA_ARGS__ "]...\n"; $p; __VA_ARGS__
15930 #define $Do( ... ) ::std::cerr << "\n[" __TX_FILELINE__ ": " #__VA_ARGS__ "]...\n"; \
15931  txMessageBox ( "\n[" __TX_FILELINE__ ": " #__VA_ARGS__ "]...\n", __TX_FUNCTION__); __VA_ARGS__
15932 
15933 #define $n { ::std::cerr << "\n"; }
15934 #define $nn { ::std::cerr << "\n\n"; }
15935 #define $t { ::std::cerr << "\t"; }
15936 
15937 #define _tx$PrefixV( ...) ( *(__VA_ARGS__ "")? ("[" __VA_ARGS__ ": " ) : ("[" ) )
15938 #define _tx$Prefix(var, ...) ( *(__VA_ARGS__ "")? ("[" __VA_ARGS__ ": " var " = ") : ("[" var " = ") )
15939 
15940 //-----------------------------------------------------------------------------------------------------------------
15941 
15942 // This will never be documented, he-he. Read the source, Luke.
15943 
15944 #if defined (_DEBUG)
15945  #define $dbg if (1)
15946  #define $DBG if (1)
15947  #define $debug if (1)
15948  #define $DEBUG if (1)
15949  #define $printf(fmt, ...) if (1) printf ( fmt, ##__VA_ARGS__)
15950  #define $PRINTF(fmt, ...) if (1) fprintf (stderr, fmt, ##__VA_ARGS__)
15951 #else
15952  #define $dbg if (0)
15953  #define $DBG if (0)
15954  #define $debug if (0)
15955  #define $DEBUG if (0)
15956  #define $printf(...) if (0) printf ( fmt, ##__VA_ARGS__)
15957  #define $PRINTF(...) if (0) fprintf (stderr, fmt, ##__VA_ARGS__)
15958 #endif
15959 
15960 #define $$d $debug
15961 #define $$w $$$$
15962 #define $$s __TX_FILELINE__
15963 #define $$b { txSleep(); DebugBreak(); }
15964 #define $$p { if (txMessageBox (__TX_FILELINE__ "\n\n" "[Повтор] - продолжение программы,\n" "[Отмена] - остановка, \ __TX_FUNCTION__, MB_ICONINFORMATION | MB_RETRYCANCEL) == IDCANCEL) ::exit (2); } #define $$P ( txMessageBox (__TX_FILELINE__, __TX_FUNCTION__, MB_ICONINFORMATION | MB_YESNOCANCEL) ) #define $ppp { $sy; txPause ("\v[%s ""%s: ""Нажмите клавишу]...", __TX_FILELINE__, __TX_FUNCTION__); } #define $pp { $sy; txPause ("\v[%04d %s: ""Нажмите клавишу]...", __LINE__, __TX_FUNCTION__); } #define $p { $sy; txPause ("\v[%s ""%s(): Нажмите клавишу]...", __TX_FILELINE__, __func__); } #define $ppp_ { $sy; txPause ("\v[%s ""%s]...", __TX_FILELINE__, __TX_FUNCTION__); } #define $pp_ { $sy; txPause ("\v[%04d %s]...", __LINE__, __TX_FUNCTION__); } #define $p_ { $sy; txPause ("\v[%s ""%s()]...", __TX_FILELINE__, __func__); } #define $P ( txPause ("") ) //----------------------------------------------------------------------------------------------------------------- struct _txSaveConsoleAttr { unsigned attr_; _txSaveConsoleAttr() : attr_ (txGetConsoleAttr ()) {} explicit _txSaveConsoleAttr (WORD attr) : attr_ (txGetConsoleAttr ()) { txSetConsoleAttr (attr); } ~_txSaveConsoleAttr() { txSetConsoleAttr (attr_); } }; //----------------------------------------------------------------------------------------------------------------- struct _txDumpVarSuffix { typedef _txDumpVarSuffix this_t; const char* suffix_; explicit _txDumpVarSuffix (const char suffix[] = "") : suffix_ (suffix) { assert (suffix); } ~_txDumpVarSuffix() { ::std::cerr << suffix_; } _txDumpVarSuffix (const this_t&) _tx_delete; this_t& operator = (const this_t&) _tx_delete; }; //----------------------------------------------------------------------------------------------------------------- #define ARGS__ const char* prefix, const char* suffix, std::ios_base::fmtflags flags, int deep #define ARGS_ const char* prefix, const char* suffix, std::ios_base::fmtflags flags = std::ios_base::fmtflags(), int deep = 0 #define VALS_ prefix, suffix, flags, deep #define ERRPTR_(p) { $sE; stream << "<НЕВЕРНЫЙ АДРЕС " << (const void*) (p) << ">"; } template <typename T, typename StreamT> const T& _txDumpVal (const T& value, StreamT& stream, ARGS_); //----------------------------------------------------------------------------------------------------------------- template <typename T> inline const T& _txDumpVar (const T& value, ARGS_) { _txDumpVal (value, std:: cerr, VALS_); return value; } template <typename T> inline T& _txDumpVar ( T& value, ARGS_) { _txDumpVal (value, std:: cerr, VALS_); return value; } template <int N> inline const char (&_txDumpVar (const char (&value) [N], ARGS_)) [N] { _txDumpVal (value, std:: cerr, VALS_); return value; } template <int N> inline char (&_txDumpVar ( char (&value) [N], ARGS_)) [N] { _txDumpVal (value, std:: cerr, VALS_); return value; } template <int N> inline const wchar_t (&_txDumpVar (const wchar_t (&value) [N], ARGS_)) [N] { _txDumpVal (value, std::wcerr, VALS_); return value; } template <int N> inline wchar_t (&_txDumpVar ( wchar_t (&value) [N], ARGS_)) [N] { _txDumpVal (value, std::wcerr, VALS_); return value; } inline const wchar_t& _txDumpVar (const wchar_t& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; } inline wchar_t& _txDumpVar ( wchar_t& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; } inline const wchar_t*& _txDumpVar (const wchar_t*& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; } inline wchar_t*& _txDumpVar ( wchar_t*& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; } inline const std::wstring& _txDumpVar (const std::wstring& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; } inline std::wstring& _txDumpVar ( std::wstring& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename StreamT> inline void _txDumpVal (const T& value, StreamT& stream) { stream << value; } template <typename StreamT> inline void _txDumpVal (const char value, StreamT& stream) { stream << "'" << value << "'"; } template <typename StreamT> inline void _txDumpVal (const wchar_t value, StreamT& stream) { stream << L"'" << value << L"'"; } template <typename StreamT> inline void _txDumpVal (const std::string& value, StreamT& stream) { stream << '"' << value << '"'; } template <typename StreamT> inline void _txDumpVal (const std::wstring& value, StreamT& stream) { stream << L'"' << value << L'"'; } template <typename StreamT> inline void _txDumpVal (const char* value, StreamT& stream) { if (_TX_ARGUMENT_FAILED (&stream)) return; if (!_txIsBadReadPtr (value)) stream << '"' << value << '"'; else if (!value) stream << "(null)"; else ERRPTR_ (value); } template <typename StreamT> inline void _txDumpVal (const wchar_t* value, StreamT& stream) { if (_TX_ARGUMENT_FAILED (&stream)) return; if (!_txIsBadReadPtr (value)) stream << L'"' << value << L'"'; else if (!value) stream << L"(null)"; else ERRPTR_ (value); } //----------------------------------------------------------------------------------------------------------------- template <typename T, typename StreamT> inline const T& _txDumpVal (const T& value, StreamT& stream, ARGS__) { if (_TX_ARGUMENT_FAILED (&stream)) return value; //-V778 if (_TX_ARGUMENT_FAILED ( prefix)) return value; if (_TX_ARGUMENT_FAILED ( suffix)) return value; $sc; if (!deep) stream << prefix; std::ios_base::fmtflags old = stream.flags ((flags)? flags : stream.flags()); if (!_txIsBadReadPtr (&value)) { _txDumpVal (value, stream); } else ERRPTR_ (&value); stream.flags (old); if (!deep) stream << suffix; return value; } //----------------------------------------------------------------------------------------------------------------- template <typename T, int N> inline T (&_txDumpVar (T (&value) [N], ARGS_)) [N] { if (_TX_ARGUMENT_FAILED ( prefix)) return value; if (_TX_ARGUMENT_FAILED ( suffix)) return value; std::ostream& stream = std::cerr; $sc; if (!deep) std::cerr << prefix; $C; std::cerr << ((deep)? " {" : "{"); if (!_txIsBadReadPtr (value)) { for (int i = 0; ; i++) { { $sC; stream << "[" << i << "]="; } _txDumpVar (value[i], prefix, suffix, flags, deep+1); if (i >= N-1) break; stream << ", "; } } else ERRPTR_ (&value); $C; std::cerr << "}"; $c; if (!deep) std::cerr << suffix; return value; } //================================================================================================================= inline std::ostream& operator << (std::ostream& stream, const POINT& point) { if (_TX_ARGUMENT_FAILED (&stream)) return stream; if (!_txIsBadReadPtr (&point)) stream << "{ x: " << point.x << ", y: " << point.y << " }"; // NOLINT (clang-diagnostic-undefined-bool-conversion) else if (!&point) stream << "(null)"; else ERRPTR_ (&point); return stream; } inline std::ostream& operator << (std::ostream& stream, const SIZE& size) { if (_TX_ARGUMENT_FAILED (&stream)) return stream; if (&size) stream << "{ cx: " << size.cx << ", cy: " << size.cy << " }"; // NOLINT (clang-diagnostic-undefined-bool-conversion) else stream << "(null)"; return stream; } inline std::ostream& operator << (std::ostream& stream, const RECT& rect) { if (_TX_ARGUMENT_FAILED (&stream)) return stream; if (&rect) stream << "{ left: " << rect.left << ", top: " << rect.top << // NOLINT (clang-diagnostic-undefined-bool-conversion) ", right: " << rect.right << ", bottom: " << rect.bottom << " }"; else stream << "(null)"; return stream; } //----------------------------------------------------------------------------------------------------------------- #undef ARGS__ #undef ARGS_ #undef VALS_ #undef ERRPTR_ //----------------------------------------------------------------------------------------------------------------- //! @endcond #endif //} //================================================================================================================= //! @cond INTERNAL //================================================================================================================= //{ TXAPI calls tracing // Трассировка вызовов TXAPI //================================================================================================================= #ifndef FOR_DOXYGEN_ONLY #if defined (_MSC_VER) #undef _txLocCurSet #define _txLocCurSet() __txLocCurSet (__FILE__, __LINE__, NULL) #endif #define txAlphaBlend(...) ( _txLocCurSet(), txAlphaBlend (__VA_ARGS__) ) #define txArc(...) ( _txLocCurSet(), txArc (__VA_ARGS__) ) #define txBegin(...) ( _txLocCurSet(), txBegin (__VA_ARGS__) ) #define txBitBlt(...) ( _txLocCurSet(), txBitBlt (__VA_ARGS__) ) #define txChord(...) ( _txLocCurSet(), txChord (__VA_ARGS__) ) #define txCircle(...) ( _txLocCurSet(), txCircle (__VA_ARGS__) ) #define txClear(...) ( _txLocCurSet(), txClear (__VA_ARGS__) ) #define txClearConsole(...) ( _txLocCurSet(), txClearConsole (__VA_ARGS__) ) #define txColor(...) ( _txLocCurSet(), txColor (__VA_ARGS__) ) #define txCreateCompatibleDC(...) ( _txLocCurSet(), txCreateCompatibleDC (__VA_ARGS__) ) #define txCreateDIBSection(...) ( _txLocCurSet(), txCreateDIBSection (__VA_ARGS__) ) #define txCreateExtraWindow(...) ( _txLocCurSet(), txCreateExtraWindow (__VA_ARGS__) ) #define txCreateWindow(...) ( _txLocCurSet(), txCreateWindow (__VA_ARGS__) ) #define txDC(...) ( _txLocCurSet(), txDC (__VA_ARGS__) ) #define txDeleteDC(...) ( _txLocCurSet(), txDeleteDC (__VA_ARGS__) ) #define txDemangle(...) ( _txLocCurSet(), txDemangle (__VA_ARGS__) ) #define txDestroyWindow(...) ( _txLocCurSet(), txDestroyWindow (__VA_ARGS__) ) #define txDisableAutoPause(...) ( _txLocCurSet(), txDisableAutoPause (__VA_ARGS__) ) #define txDrawText(...) ( _txLocCurSet(), txDrawText (__VA_ARGS__) ) #define txEllipse(...) ( _txLocCurSet(), txEllipse (__VA_ARGS__) ) #define txEnd(...) ( _txLocCurSet(), txEnd (__VA_ARGS__) ) #define txExtractColor(...) ( _txLocCurSet(), txExtractColor (__VA_ARGS__) ) #define txFillColor(...) ( _txLocCurSet(), txFillColor (__VA_ARGS__) ) #define txFloodFill(...) ( _txLocCurSet(), txFloodFill (__VA_ARGS__) ) #define txFontExist(...) ( _txLocCurSet(), txFontExist (__VA_ARGS__) ) #define txFormat(...) ( _txLocCurSet(), txFormat (__VA_ARGS__) ) #define txGetAsyncKeyState(...) ( _txLocCurSet(), txGetAsyncKeyState (__VA_ARGS__) ) #define txGetColor(...) ( _txLocCurSet(), txGetColor (__VA_ARGS__) ) #define txGetConsoleAttr(...) ( _txLocCurSet(), txGetConsoleAttr (__VA_ARGS__) ) #define txGetConsoleCursorPos(...) ( _txLocCurSet(), txGetConsoleCursorPos (__VA_ARGS__) ) #define txGetConsoleExtent(...) ( _txLocCurSet(), txGetConsoleExtent (__VA_ARGS__) ) #define txGetConsoleFontSize(...) ( _txLocCurSet(), txGetConsoleFontSize (__VA_ARGS__) ) #define txGetExtent(...) ( _txLocCurSet(), txGetExtent (__VA_ARGS__) ) #define txGetExtentX(...) ( _txLocCurSet(), txGetExtentX (__VA_ARGS__) ) #define txGetExtentY(...) ( _txLocCurSet(), txGetExtentY (__VA_ARGS__) ) #define txGetFillColor(...) ( _txLocCurSet(), txGetFillColor (__VA_ARGS__) ) #define txGetFPS(...) ( _txLocCurSet(), txGetFPS (__VA_ARGS__) ) #define txGetModuleFileName(...) ( _txLocCurSet(), txGetModuleFileName (__VA_ARGS__) ) #define txGetPixel(...) ( _txLocCurSet(), txGetPixel (__VA_ARGS__) ) #define txGetTextExtent(...) ( _txLocCurSet(), txGetTextExtent (__VA_ARGS__) ) #define txGetTextExtentX(...) ( _txLocCurSet(), txGetTextExtentX (__VA_ARGS__) ) #define txGetTextExtentY(...) ( _txLocCurSet(), txGetTextExtentY (__VA_ARGS__) ) #define txHSL2RGB(...) ( _txLocCurSet(), txHSL2RGB (__VA_ARGS__) ) #define txInputBox(...) ( _txLocCurSet(), txInputBox (__VA_ARGS__) ) #define txLine(...) ( _txLocCurSet(), txLine (__VA_ARGS__) ) #define txLoadImage(...) ( _txLocCurSet(), txLoadImage (__VA_ARGS__) ) #define txLock(...) ( _txLocCurSet(), txLock (__VA_ARGS__) ) #define txMessageBox(...) ( _txLocCurSet(), txMessageBox (__VA_ARGS__) ) #define txMouseButtons(...) ( _txLocCurSet(), txMouseButtons (__VA_ARGS__) ) #define txMousePos(...) ( _txLocCurSet(), txMousePos (__VA_ARGS__) ) #define txMouseX(...) ( _txLocCurSet(), txMouseX (__VA_ARGS__) ) #define txMouseY(...) ( _txLocCurSet(), txMouseY (__VA_ARGS__) ) #define txNotifyIcon(...) ( _txLocCurSet(), txNotifyIcon (__VA_ARGS__) ) #define txOK(...) ( _txLocCurSet(), txOK (__VA_ARGS__) ) #define txOutputDebugPrintf(...) ( _txLocCurSet(), txOutputDebugPrintf (__VA_ARGS__) ) #define txPause(...) ( _txLocCurSet(), txPause (__VA_ARGS__) ) #define txPie(...) ( _txLocCurSet(), txPie (__VA_ARGS__) ) #define txPixel(...) ( _txLocCurSet(), txPixel (__VA_ARGS__) ) #define txPlaySound(...) ( _txLocCurSet(), txPlaySound (__VA_ARGS__) ) #define txPlayVideo(...) ( _txLocCurSet(), txPlayVideo (__VA_ARGS__) ) #define txPolygon(...) ( _txLocCurSet(), txPolygon (__VA_ARGS__) ) #define txPrintf(...) ( _txLocCurSet(), txPrintf (__VA_ARGS__) ) #define txQueryPerformance(...) ( _txLocCurSet(), txQueryPerformance (__VA_ARGS__) ) #define txRectangle(...) ( _txLocCurSet(), txRectangle (__VA_ARGS__) ) #define txRedrawWindow(...) ( _txLocCurSet(), txRedrawWindow (__VA_ARGS__) ) #define txRegisterClass(...) ( _txLocCurSet(), txRegisterClass (__VA_ARGS__) ) #define txRegQuery(...) ( _txLocCurSet(), txRegQuery (__VA_ARGS__) ) #define txReopenStdio(...) ( _txLocCurSet(), txReopenStdio (__VA_ARGS__) ) #define txRGB2HSL(...) ( _txLocCurSet(), txRGB2HSL (__VA_ARGS__) ) #define txSaveImage(...) ( _txLocCurSet(), txSaveImage (__VA_ARGS__) ) #define txSelectFont(...) ( _txLocCurSet(), txSelectFont (__VA_ARGS__) ) #define txSelectObject(...) ( _txLocCurSet(), txSelectObject (__VA_ARGS__) ) #define txSetColor(...) ( _txLocCurSet(), txSetColor (__VA_ARGS__) ) #define txSetConsoleAttr(...) ( _txLocCurSet(), txSetConsoleAttr (__VA_ARGS__) ) #define txSetConsoleCursorPos(...) ( _txLocCurSet(), txSetConsoleCursorPos (__VA_ARGS__) ) #define txSetDefaults(...) ( _txLocCurSet(), txSetDefaults (__VA_ARGS__) ) #define txSetFillColor(...) ( _txLocCurSet(), txSetFillColor (__VA_ARGS__) ) #define txSetLocale(...) ( _txLocCurSet(), txSetLocale (__VA_ARGS__) ) #define txSetPixel(...) ( _txLocCurSet(), txSetPixel (__VA_ARGS__) ) #define txSetProgress(...) ( _txLocCurSet(), txSetProgress (__VA_ARGS__) ) #define txSetTextAlign(...) ( _txLocCurSet(), txSetTextAlign (__VA_ARGS__) ) #define txSetWindowsHook(...) ( _txLocCurSet(), txSetWindowsHook (__VA_ARGS__) ) #define txSleep(...) ( _txLocCurSet(), txSleep (__VA_ARGS__) ) #define txSpeak(...) ( _txLocCurSet(), txSpeak (__VA_ARGS__) ) #define txTextCursor(...) ( _txLocCurSet(), txTextCursor (__VA_ARGS__) ) #define txTextOut(...) ( _txLocCurSet(), txTextOut (__VA_ARGS__) ) #define txTransparentBlt(...) ( _txLocCurSet(), txTransparentBlt (__VA_ARGS__) ) #define txTriangle(...) ( _txLocCurSet(), txTriangle (__VA_ARGS__) ) #define txUnlock(...) ( _txLocCurSet(), txUnlock (__VA_ARGS__) ) #define txUpdateWindow(...) ( _txLocCurSet(), txUpdateWindow (__VA_ARGS__) ) #define txUseAlpha(...) ( _txLocCurSet(), txUseAlpha (__VA_ARGS__) ) #define txVersion(...) ( _txLocCurSet(), txVersion (__VA_ARGS__) ) #define txVersionNumber(...) ( _txLocCurSet(), txVersionNumber (__VA_ARGS__) ) #define txWindow(...) ( _txLocCurSet(), txWindow (__VA_ARGS__) ) #define tx_fpreset(...) ( _txLocCurSet(), tx_fpreset (__VA_ARGS__) ) #define tx_glGetError(...) ( _txLocCurSet(), tx_glGetError (__VA_ARGS__) ) #define _txDump(...) ( _txLocCurSet(), _txDump (__VA_ARGS__) ) #define _txStackBackTrace(...) ( _txLocCurSet(), _txStackBackTrace (__VA_ARGS__) ) #endif //} //================================================================================================================= //! @endcond //} //================================================================================================================= //----------------------------------------------------------------------------------------------------------------- //{ The namespaces //----------------------------------------------------------------------------------------------------------------- /*! @cond INTERNAL */ _TX_END_NAMESPACE /*! @endcond */ using namespace TX; // Allow easy usage of TXLib functions using ::std::cin; // Predefined usings to avoid "using namespace std" using ::std::cout; using ::std::cerr; using ::std::string; using ::std::wcin; using ::std::wcout; using ::std::wcerr; using ::std::wstring; //} //----------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------- //{ Compiler- and platform-specific // Адаптация к компиляторам и платформам //----------------------------------------------------------------------------------------------------------------- //! @cond INTERNAL #if defined (_GCC_VER) #pragma GCC optimize "strict-aliasing" #pragma GCC pop_options #pragma GCC diagnostic pop #endif #if defined (_CLANG_VER) #pragma clang diagnostic pop #endif //----------------------------------------------------------------------------------------------------------------- #if defined (_MSC_VER) #pragma warning (pop) // Restoring maximum level #endif #if defined (__INTEL_COMPILER) #pragma warning (default: 174) // Remark: expression has no effect #pragma warning (default: 304) // Remark: access control not specified ("public" by default) #pragma warning (default: 444) // Remark: destructor for base class "..." is not virtual #pragma warning (default: 522) // Remark: function redeclared "inline" after being called #pragma warning (default: 1684) // Conversion from pointer to same-sized integral type (potential portability problem) #pragma warning (disable: 981) // Remark: operands are evaluated in unspecified order #endif //! @endcond //} //----------------------------------------------------------------------------------------------------------------- #endif // __TXLIB_H_INCLUDED //================================================================================================================= // EOF //================================================================================================================= ", \
15965  __TX_FUNCTION__, MB_ICONINFORMATION | MB_RETRYCANCEL) == IDCANCEL) ::exit (2); }
15966 #define $$P ( txMessageBox (__TX_FILELINE__, __TX_FUNCTION__, MB_ICONINFORMATION | MB_YESNOCANCEL) )
15967 #define $ppp { $sy; txPause ("\v[%s ""%s: ""Нажмите клавишу]...", __TX_FILELINE__, __TX_FUNCTION__); }
15968 #define $pp { $sy; txPause ("\v[%04d %s: ""Нажмите клавишу]...", __LINE__, __TX_FUNCTION__); }
15969 #define $p { $sy; txPause ("\v[%s ""%s(): Нажмите клавишу]...", __TX_FILELINE__, __func__); }
15970 #define $ppp_ { $sy; txPause ("\v[%s ""%s]...", __TX_FILELINE__, __TX_FUNCTION__); }
15971 #define $pp_ { $sy; txPause ("\v[%04d %s]...", __LINE__, __TX_FUNCTION__); }
15972 #define $p_ { $sy; txPause ("\v[%s ""%s()]...", __TX_FILELINE__, __func__); }
15973 #define $P ( txPause ("") )
15974 
15975 //-----------------------------------------------------------------------------------------------------------------
15976 
15977 struct _txSaveConsoleAttr
15978  {
15979  unsigned attr_;
15980 
15981  _txSaveConsoleAttr() : attr_ (txGetConsoleAttr ()) {}
15982  explicit _txSaveConsoleAttr (WORD attr) : attr_ (txGetConsoleAttr ()) { txSetConsoleAttr (attr); }
15983  ~_txSaveConsoleAttr() { txSetConsoleAttr (attr_); }
15984  };
15985 
15986 //-----------------------------------------------------------------------------------------------------------------
15987 
15988 struct _txDumpVarSuffix
15989  {
15990  typedef _txDumpVarSuffix this_t;
15991 
15992  const char* suffix_;
15993 
15994  explicit _txDumpVarSuffix (const char suffix[] = "") : suffix_ (suffix) { assert (suffix); }
15995  ~_txDumpVarSuffix() { ::std::cerr << suffix_; }
15996 
15997  _txDumpVarSuffix (const this_t&) _tx_delete;
15998  this_t& operator = (const this_t&) _tx_delete;
15999  };
16000 
16001 //-----------------------------------------------------------------------------------------------------------------
16002 
16003 #define ARGS__ const char* prefix, const char* suffix, std::ios_base::fmtflags flags, int deep
16004 #define ARGS_ const char* prefix, const char* suffix, std::ios_base::fmtflags flags = std::ios_base::fmtflags(), int deep = 0
16005 #define VALS_ prefix, suffix, flags, deep
16006 #define ERRPTR_(p) { $sE; stream << "<НЕВЕРНЫЙ АДРЕС " << (const void*) (p) << ">"; }
16007 
16008 template <typename T, typename StreamT> const T& _txDumpVal (const T& value, StreamT& stream, ARGS_);
16009 
16010 //-----------------------------------------------------------------------------------------------------------------
16011 
16012 template <typename T> inline const T& _txDumpVar (const T& value, ARGS_) { _txDumpVal (value, std:: cerr, VALS_); return value; }
16013 template <typename T> inline T& _txDumpVar ( T& value, ARGS_) { _txDumpVal (value, std:: cerr, VALS_); return value; }
16014 
16015 template <int N> inline const char (&_txDumpVar (const char (&value) [N], ARGS_)) [N] { _txDumpVal (value, std:: cerr, VALS_); return value; }
16016 template <int N> inline char (&_txDumpVar ( char (&value) [N], ARGS_)) [N] { _txDumpVal (value, std:: cerr, VALS_); return value; }
16017 
16018 template <int N> inline const wchar_t (&_txDumpVar (const wchar_t (&value) [N], ARGS_)) [N] { _txDumpVal (value, std::wcerr, VALS_); return value; }
16019 template <int N> inline wchar_t (&_txDumpVar ( wchar_t (&value) [N], ARGS_)) [N] { _txDumpVal (value, std::wcerr, VALS_); return value; }
16020 
16021  inline const wchar_t& _txDumpVar (const wchar_t& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; }
16022  inline wchar_t& _txDumpVar ( wchar_t& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; }
16023 
16024  inline const wchar_t*& _txDumpVar (const wchar_t*& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; }
16025  inline wchar_t*& _txDumpVar ( wchar_t*& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; }
16026 
16027  inline const std::wstring& _txDumpVar (const std::wstring& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; }
16028  inline std::wstring& _txDumpVar ( std::wstring& value, ARGS_) { _txDumpVal (value, std::wcerr, VALS_); return value; }
16029 
16030 //-----------------------------------------------------------------------------------------------------------------
16031 
16032 template <typename T, typename StreamT> inline void _txDumpVal (const T& value, StreamT& stream) { stream << value; }
16033 template <typename StreamT> inline void _txDumpVal (const char value, StreamT& stream) { stream << "'" << value << "'"; }
16034 template <typename StreamT> inline void _txDumpVal (const wchar_t value, StreamT& stream) { stream << L"'" << value << L"'"; }
16035 template <typename StreamT> inline void _txDumpVal (const std::string& value, StreamT& stream) { stream << '"' << value << '"'; }
16036 template <typename StreamT> inline void _txDumpVal (const std::wstring& value, StreamT& stream) { stream << L'"' << value << L'"'; }
16037 
16038 template <typename StreamT> inline void _txDumpVal (const char* value, StreamT& stream)
16039  {
16040  if (_TX_ARGUMENT_FAILED (&stream)) return;
16041 
16042  if (!_txIsBadReadPtr (value)) stream << '"' << value << '"';
16043  else if (!value) stream << "(null)";
16044  else ERRPTR_ (value);
16045  }
16046 
16047 template <typename StreamT> inline void _txDumpVal (const wchar_t* value, StreamT& stream)
16048  {
16049  if (_TX_ARGUMENT_FAILED (&stream)) return;
16050 
16051  if (!_txIsBadReadPtr (value)) stream << L'"' << value << L'"';
16052  else if (!value) stream << L"(null)";
16053  else ERRPTR_ (value);
16054  }
16055 
16056 //-----------------------------------------------------------------------------------------------------------------
16057 
16058 template <typename T, typename StreamT>
16059 inline const T& _txDumpVal (const T& value, StreamT& stream, ARGS__)
16060  {
16061  if (_TX_ARGUMENT_FAILED (&stream)) return value; //-V778
16062  if (_TX_ARGUMENT_FAILED ( prefix)) return value;
16063  if (_TX_ARGUMENT_FAILED ( suffix)) return value;
16064 
16065  $sc;
16066  if (!deep) stream << prefix;
16067 
16068  std::ios_base::fmtflags old = stream.flags ((flags)? flags : stream.flags());
16069 
16070  if (!_txIsBadReadPtr (&value))
16071  {
16072  _txDumpVal (value, stream);
16073  }
16074  else
16075  ERRPTR_ (&value);
16076 
16077  stream.flags (old);
16078 
16079  if (!deep) stream << suffix;
16080 
16081  return value;
16082  }
16083 
16084 //-----------------------------------------------------------------------------------------------------------------
16085 
16086 template <typename T, int N>
16087 inline T (&_txDumpVar (T (&value) [N], ARGS_)) [N]
16088  {
16089  if (_TX_ARGUMENT_FAILED ( prefix)) return value;
16090  if (_TX_ARGUMENT_FAILED ( suffix)) return value;
16091 
16092  std::ostream& stream = std::cerr;
16093 
16094  $sc; if (!deep) std::cerr << prefix;
16095  $C; std::cerr << ((deep)? " {" : "{");
16096 
16097  if (!_txIsBadReadPtr (value))
16098  {
16099  for (int i = 0; ; i++)
16100  {
16101  { $sC; stream << "[" << i << "]="; }
16102 
16103  _txDumpVar (value[i], prefix, suffix, flags, deep+1);
16104 
16105  if (i >= N-1) break;
16106 
16107  stream << ", ";
16108  }
16109  }
16110  else
16111  ERRPTR_ (&value);
16112 
16113  $C; std::cerr << "}";
16114  $c; if (!deep) std::cerr << suffix;
16115 
16116  return value;
16117  }
16118 
16119 //=================================================================================================================
16120 
16121 inline std::ostream& operator << (std::ostream& stream, const POINT& point)
16122  {
16123  if (_TX_ARGUMENT_FAILED (&stream)) return stream;
16124 
16125  if (!_txIsBadReadPtr (&point)) stream << "{ x: " << point.x << ", y: " << point.y << " }"; // NOLINT (clang-diagnostic-undefined-bool-conversion)
16126  else if (!&point) stream << "(null)";
16127  else ERRPTR_ (&point);
16128 
16129  return stream;
16130  }
16131 
16132 inline std::ostream& operator << (std::ostream& stream, const SIZE& size)
16133  {
16134  if (_TX_ARGUMENT_FAILED (&stream)) return stream;
16135 
16136  if (&size) stream << "{ cx: " << size.cx << ", cy: " << size.cy << " }"; // NOLINT (clang-diagnostic-undefined-bool-conversion)
16137  else stream << "(null)";
16138 
16139  return stream;
16140  }
16141 
16142 inline std::ostream& operator << (std::ostream& stream, const RECT& rect)
16143  {
16144  if (_TX_ARGUMENT_FAILED (&stream)) return stream;
16145 
16146  if (&rect) stream << "{ left: " << rect.left << ", top: " << rect.top << // NOLINT (clang-diagnostic-undefined-bool-conversion)
16147  ", right: " << rect.right << ", bottom: " << rect.bottom << " }";
16148 
16149  else stream << "(null)";
16150 
16151  return stream;
16152  }
16153 
16154 //-----------------------------------------------------------------------------------------------------------------
16155 
16156 #undef ARGS__
16157 #undef ARGS_
16158 #undef VALS_
16159 #undef ERRPTR_
16160 
16161 //-----------------------------------------------------------------------------------------------------------------
16163 
16164 #endif
16165 
16166 //}
16167 //=================================================================================================================
16168 
16170 
16171 //=================================================================================================================
16172 //{ TXAPI calls tracing
16173 // Трассировка вызовов TXAPI
16174 //=================================================================================================================
16175 
16176 #ifndef FOR_DOXYGEN_ONLY
16177 
16178 #if defined (_MSC_VER)
16179 #undef _txLocCurSet
16180 #define _txLocCurSet() __txLocCurSet (__FILE__, __LINE__, NULL)
16181 #endif
16182 
16183 #define txAlphaBlend(...) ( _txLocCurSet(), txAlphaBlend (__VA_ARGS__) )
16184 #define txArc(...) ( _txLocCurSet(), txArc (__VA_ARGS__) )
16185 #define txBegin(...) ( _txLocCurSet(), txBegin (__VA_ARGS__) )
16186 #define txBitBlt(...) ( _txLocCurSet(), txBitBlt (__VA_ARGS__) )
16187 #define txChord(...) ( _txLocCurSet(), txChord (__VA_ARGS__) )
16188 #define txCircle(...) ( _txLocCurSet(), txCircle (__VA_ARGS__) )
16189 #define txClear(...) ( _txLocCurSet(), txClear (__VA_ARGS__) )
16190 #define txClearConsole(...) ( _txLocCurSet(), txClearConsole (__VA_ARGS__) )
16191 #define txColor(...) ( _txLocCurSet(), txColor (__VA_ARGS__) )
16192 #define txCreateCompatibleDC(...) ( _txLocCurSet(), txCreateCompatibleDC (__VA_ARGS__) )
16193 #define txCreateDIBSection(...) ( _txLocCurSet(), txCreateDIBSection (__VA_ARGS__) )
16194 #define txCreateExtraWindow(...) ( _txLocCurSet(), txCreateExtraWindow (__VA_ARGS__) )
16195 #define txCreateWindow(...) ( _txLocCurSet(), txCreateWindow (__VA_ARGS__) )
16196 #define txDC(...) ( _txLocCurSet(), txDC (__VA_ARGS__) )
16197 #define txDeleteDC(...) ( _txLocCurSet(), txDeleteDC (__VA_ARGS__) )
16198 #define txDemangle(...) ( _txLocCurSet(), txDemangle (__VA_ARGS__) )
16199 #define txDestroyWindow(...) ( _txLocCurSet(), txDestroyWindow (__VA_ARGS__) )
16200 #define txDisableAutoPause(...) ( _txLocCurSet(), txDisableAutoPause (__VA_ARGS__) )
16201 #define txDrawText(...) ( _txLocCurSet(), txDrawText (__VA_ARGS__) )
16202 #define txEllipse(...) ( _txLocCurSet(), txEllipse (__VA_ARGS__) )
16203 #define txEnd(...) ( _txLocCurSet(), txEnd (__VA_ARGS__) )
16204 #define txExtractColor(...) ( _txLocCurSet(), txExtractColor (__VA_ARGS__) )
16205 #define txFillColor(...) ( _txLocCurSet(), txFillColor (__VA_ARGS__) )
16206 #define txFloodFill(...) ( _txLocCurSet(), txFloodFill (__VA_ARGS__) )
16207 #define txFontExist(...) ( _txLocCurSet(), txFontExist (__VA_ARGS__) )
16208 #define txFormat(...) ( _txLocCurSet(), txFormat (__VA_ARGS__) )
16209 #define txGetAsyncKeyState(...) ( _txLocCurSet(), txGetAsyncKeyState (__VA_ARGS__) )
16210 #define txGetColor(...) ( _txLocCurSet(), txGetColor (__VA_ARGS__) )
16211 #define txGetConsoleAttr(...) ( _txLocCurSet(), txGetConsoleAttr (__VA_ARGS__) )
16212 #define txGetConsoleCursorPos(...) ( _txLocCurSet(), txGetConsoleCursorPos (__VA_ARGS__) )
16213 #define txGetConsoleExtent(...) ( _txLocCurSet(), txGetConsoleExtent (__VA_ARGS__) )
16214 #define txGetConsoleFontSize(...) ( _txLocCurSet(), txGetConsoleFontSize (__VA_ARGS__) )
16215 #define txGetExtent(...) ( _txLocCurSet(), txGetExtent (__VA_ARGS__) )
16216 #define txGetExtentX(...) ( _txLocCurSet(), txGetExtentX (__VA_ARGS__) )
16217 #define txGetExtentY(...) ( _txLocCurSet(), txGetExtentY (__VA_ARGS__) )
16218 #define txGetFillColor(...) ( _txLocCurSet(), txGetFillColor (__VA_ARGS__) )
16219 #define txGetFPS(...) ( _txLocCurSet(), txGetFPS (__VA_ARGS__) )
16220 #define txGetModuleFileName(...) ( _txLocCurSet(), txGetModuleFileName (__VA_ARGS__) )
16221 #define txGetPixel(...) ( _txLocCurSet(), txGetPixel (__VA_ARGS__) )
16222 #define txGetTextExtent(...) ( _txLocCurSet(), txGetTextExtent (__VA_ARGS__) )
16223 #define txGetTextExtentX(...) ( _txLocCurSet(), txGetTextExtentX (__VA_ARGS__) )
16224 #define txGetTextExtentY(...) ( _txLocCurSet(), txGetTextExtentY (__VA_ARGS__) )
16225 #define txHSL2RGB(...) ( _txLocCurSet(), txHSL2RGB (__VA_ARGS__) )
16226 #define txInputBox(...) ( _txLocCurSet(), txInputBox (__VA_ARGS__) )
16227 #define txLine(...) ( _txLocCurSet(), txLine (__VA_ARGS__) )
16228 #define txLoadImage(...) ( _txLocCurSet(), txLoadImage (__VA_ARGS__) )
16229 #define txLock(...) ( _txLocCurSet(), txLock (__VA_ARGS__) )
16230 #define txMessageBox(...) ( _txLocCurSet(), txMessageBox (__VA_ARGS__) )
16231 #define txMouseButtons(...) ( _txLocCurSet(), txMouseButtons (__VA_ARGS__) )
16232 #define txMousePos(...) ( _txLocCurSet(), txMousePos (__VA_ARGS__) )
16233 #define txMouseX(...) ( _txLocCurSet(), txMouseX (__VA_ARGS__) )
16234 #define txMouseY(...) ( _txLocCurSet(), txMouseY (__VA_ARGS__) )
16235 #define txNotifyIcon(...) ( _txLocCurSet(), txNotifyIcon (__VA_ARGS__) )
16236 #define txOK(...) ( _txLocCurSet(), txOK (__VA_ARGS__) )
16237 #define txOutputDebugPrintf(...) ( _txLocCurSet(), txOutputDebugPrintf (__VA_ARGS__) )
16238 #define txPause(...) ( _txLocCurSet(), txPause (__VA_ARGS__) )
16239 #define txPie(...) ( _txLocCurSet(), txPie (__VA_ARGS__) )
16240 #define txPixel(...) ( _txLocCurSet(), txPixel (__VA_ARGS__) )
16241 #define txPlaySound(...) ( _txLocCurSet(), txPlaySound (__VA_ARGS__) )
16242 #define txPlayVideo(...) ( _txLocCurSet(), txPlayVideo (__VA_ARGS__) )
16243 #define txPolygon(...) ( _txLocCurSet(), txPolygon (__VA_ARGS__) )
16244 #define txPrintf(...) ( _txLocCurSet(), txPrintf (__VA_ARGS__) )
16245 #define txQueryPerformance(...) ( _txLocCurSet(), txQueryPerformance (__VA_ARGS__) )
16246 #define txRectangle(...) ( _txLocCurSet(), txRectangle (__VA_ARGS__) )
16247 #define txRedrawWindow(...) ( _txLocCurSet(), txRedrawWindow (__VA_ARGS__) )
16248 #define txRegisterClass(...) ( _txLocCurSet(), txRegisterClass (__VA_ARGS__) )
16249 #define txRegQuery(...) ( _txLocCurSet(), txRegQuery (__VA_ARGS__) )
16250 #define txReopenStdio(...) ( _txLocCurSet(), txReopenStdio (__VA_ARGS__) )
16251 #define txRGB2HSL(...) ( _txLocCurSet(), txRGB2HSL (__VA_ARGS__) )
16252 #define txSaveImage(...) ( _txLocCurSet(), txSaveImage (__VA_ARGS__) )
16253 #define txSelectFont(...) ( _txLocCurSet(), txSelectFont (__VA_ARGS__) )
16254 #define txSelectObject(...) ( _txLocCurSet(), txSelectObject (__VA_ARGS__) )
16255 #define txSetColor(...) ( _txLocCurSet(), txSetColor (__VA_ARGS__) )
16256 #define txSetConsoleAttr(...) ( _txLocCurSet(), txSetConsoleAttr (__VA_ARGS__) )
16257 #define txSetConsoleCursorPos(...) ( _txLocCurSet(), txSetConsoleCursorPos (__VA_ARGS__) )
16258 #define txSetDefaults(...) ( _txLocCurSet(), txSetDefaults (__VA_ARGS__) )
16259 #define txSetFillColor(...) ( _txLocCurSet(), txSetFillColor (__VA_ARGS__) )
16260 #define txSetLocale(...) ( _txLocCurSet(), txSetLocale (__VA_ARGS__) )
16261 #define txSetPixel(...) ( _txLocCurSet(), txSetPixel (__VA_ARGS__) )
16262 #define txSetProgress(...) ( _txLocCurSet(), txSetProgress (__VA_ARGS__) )
16263 #define txSetTextAlign(...) ( _txLocCurSet(), txSetTextAlign (__VA_ARGS__) )
16264 #define txSetWindowsHook(...) ( _txLocCurSet(), txSetWindowsHook (__VA_ARGS__) )
16265 #define txSleep(...) ( _txLocCurSet(), txSleep (__VA_ARGS__) )
16266 #define txSpeak(...) ( _txLocCurSet(), txSpeak (__VA_ARGS__) )
16267 #define txTextCursor(...) ( _txLocCurSet(), txTextCursor (__VA_ARGS__) )
16268 #define txTextOut(...) ( _txLocCurSet(), txTextOut (__VA_ARGS__) )
16269 #define txTransparentBlt(...) ( _txLocCurSet(), txTransparentBlt (__VA_ARGS__) )
16270 #define txTriangle(...) ( _txLocCurSet(), txTriangle (__VA_ARGS__) )
16271 #define txUnlock(...) ( _txLocCurSet(), txUnlock (__VA_ARGS__) )
16272 #define txUpdateWindow(...) ( _txLocCurSet(), txUpdateWindow (__VA_ARGS__) )
16273 #define txUseAlpha(...) ( _txLocCurSet(), txUseAlpha (__VA_ARGS__) )
16274 #define txVersion(...) ( _txLocCurSet(), txVersion (__VA_ARGS__) )
16275 #define txVersionNumber(...) ( _txLocCurSet(), txVersionNumber (__VA_ARGS__) )
16276 #define txWindow(...) ( _txLocCurSet(), txWindow (__VA_ARGS__) )
16277 #define tx_fpreset(...) ( _txLocCurSet(), tx_fpreset (__VA_ARGS__) )
16278 #define tx_glGetError(...) ( _txLocCurSet(), tx_glGetError (__VA_ARGS__) )
16279 #define _txDump(...) ( _txLocCurSet(), _txDump (__VA_ARGS__) )
16280 #define _txStackBackTrace(...) ( _txLocCurSet(), _txStackBackTrace (__VA_ARGS__) )
16281 
16282 #endif
16283 
16284 //}
16285 //=================================================================================================================
16286 
16288 //}
16289 //=================================================================================================================
16290 
16291 //-----------------------------------------------------------------------------------------------------------------
16292 //{ The namespaces
16293 //-----------------------------------------------------------------------------------------------------------------
16294 
16297 _TX_END_NAMESPACE
16298 
16301 using namespace TX; // Allow easy usage of TXLib functions
16302 
16303 using ::std::cin; // Predefined usings to avoid "using namespace std"
16304 using ::std::cout;
16305 using ::std::cerr;
16306 using ::std::string;
16307 using ::std::wcin;
16308 using ::std::wcout;
16309 using ::std::wcerr;
16310 using ::std::wstring;
16311 
16312 //}
16313 //-----------------------------------------------------------------------------------------------------------------
16314 
16315 //-----------------------------------------------------------------------------------------------------------------
16316 //{ Compiler- and platform-specific
16317 // Адаптация к компиляторам и платформам
16318 //-----------------------------------------------------------------------------------------------------------------
16320 
16321 #if defined (_GCC_VER)
16322 
16323  #pragma GCC optimize "strict-aliasing"
16324 
16325  #pragma GCC pop_options
16326  #pragma GCC diagnostic pop
16327 
16328  #endif
16329 
16330 #if defined (_CLANG_VER)
16331 
16332  #pragma clang diagnostic pop
16333 
16334  #endif
16335 
16336 //-----------------------------------------------------------------------------------------------------------------
16337 
16338 #if defined (_MSC_VER)
16339 
16340  #pragma warning (pop) // Restoring maximum level
16341 
16342  #endif
16343 
16344 #if defined (__INTEL_COMPILER)
16345 
16346  #pragma warning (default: 174) // Remark: expression has no effect
16347  #pragma warning (default: 304) // Remark: access control not specified ("public" by default)
16348  #pragma warning (default: 444) // Remark: destructor for base class "..." is not virtual
16349  #pragma warning (default: 522) // Remark: function redeclared "inline" after being called
16350  #pragma warning (default: 1684) // Conversion from pointer to same-sized integral type (potential portability problem)
16351 
16352  #pragma warning (disable: 981) // Remark: operands are evaluated in unspecified order
16353 
16354  #endif
16355 
16357 //}
16358 //-----------------------------------------------------------------------------------------------------------------
16359 
16360 #endif // __TXLIB_H_INCLUDED
16361 
16362 //=================================================================================================================
16363 // EOF
16364 //=================================================================================================================
16365 
16366 
16367 
16368 
16369 
16370 
16371 
16372 
16373 
16374 
16375 
16376 
16377 
16378 
16379 
16380 
16381 
16382 
16383 
16384 
16385 
16386 
16387 
16388 
16389 
16390 
16391 
16392 
16393 
16394 
16395 
16396 
16397 
16398 
16399 
Класс для автоматической блокировки и разблокировки критической секции.
Definition: TXLib.h:6358
~txAutoLock()
Деструктор, разблокирует секцию
Definition: TXLib.h:6422
txAutoLock(bool mandatory=true)
Конструктор для блокировки холста TXLib.
Definition: TXLib.h:6412
CRITICAL_SECTION * cs_
Блокируемая критическая секция
Definition: TXLib.h:6443
txAutoLock(CRITICAL_SECTION *cs, bool mandatory=true)
Конструктор, блокирует критическую секцию
Definition: TXLib.h:6388
CONTROL
Константы для задания типа контрола.
Definition: TXLib.h:6510
const char * txInputBox(const char *text=NULL, const char *caption=NULL, const char *input=NULL) tx_nodiscard
Ввод строки в отдельном окне.
Definition: TXLib.h:6846
@ DIALOG
Начало описания диалога
Definition: TXLib.h:6511
@ END
Конец описания диалога
Definition: TXLib.h:6518
@ COMBOBOX
Комбинированный список
Definition: TXLib.h:6517
@ LISTBOX
Список с прокруткой
Definition: TXLib.h:6515
@ BUTTON
Кнопка
Definition: TXLib.h:6512
@ STATIC
Нередактируемый элемент (текст, картинка и т.д.)
Definition: TXLib.h:6514
@ EDIT
Редактируемый текст
Definition: TXLib.h:6513
@ SCROLLBAR
Полоса прокрутки
Definition: TXLib.h:6516
const COLORREF TX_LIGHTNESS
Светлота цвета в модели HSL, [0; 255].
Definition: TXLib.h:1491
unsigned txSetTextAlign(unsigned align=TA_CENTER|TA_BASELINE, HDC dc=txDC())
Устанавливает текущее выравнивание текста (влево/вправо/по центру).
bool txDestroyWindow(HWND wnd=txWindow())
Уничтожает окно.
POINT txGetExtent(HDC dc=txDC()) tx_nodiscard
Возвращает размер окна, картинки или холста в виде структуры POINT.
const char * txGetModuleFileName(bool fileNameOnly=true) tx_nodiscard
Возвращает имя исполняемого файла или изначальный заголовок окна TXLib.
COLORREF txRGB2HSL(COLORREF rgbColor) tx_nodiscard
Преобразует цвет из формата RGB в формат HSL.
const COLORREF TX_DARKGRAY
Темно-серый цвет.
Definition: TXLib.h:1472
bool txRectangle(double x0, double y0, double x1, double y1, HDC dc=txDC())
Рисует прямоугольник.
double txGetFPS(int minFrames=txFramesToAverage) tx_nodiscard
Выдает количество кадров (вызовов этой функции) в секунду.
const COLORREF TX_BLM
Альтернативный политкорректный трендовый цвет!
Definition: TXLib.h:1484
POINT txGetConsoleFontSize() tx_nodiscard
Возвращает размеры шрифта консоли.
const COLORREF TX_LIGHTGREEN
Светло-зеленый цвет.
Definition: TXLib.h:1475
bool txClearConsole()
Стирает текст консоли.
HDC txLoadImage(const char filename[], int sizeX=0, int sizeY=0, unsigned imageFlags=IMAGE_BITMAP, unsigned loadFlags=LR_LOADFROMFILE) tx_nodiscard
Загружает из файла изображение в формате BMP. Делает это довольно медленно.
POINT txGetConsoleCursorPos()
Возвращает позицию мигающего курсора консоли.
bool txOK() tx_nodiscard
Проверка правильности работы библиотеки
const COLORREF TX_GREEN
Зеленый цвет.
Definition: TXLib.h:1465
const COLORREF TX_LIGHTBLUE
Светло-синий цвет.
Definition: TXLib.h:1474
RGBQUAD * txVideoMemory() tx_nodiscard
Возвращает буфер памяти, связанный с холстом (HDC) TXLib.
const COLORREF TX_SATURATION
Насыщенность цвета в модели HSL, [0; 255].
Definition: TXLib.h:1490
bool txSaveImage(const char filename[], HDC dc=txDC())
Сохраняет в файл изображение в формате BMP.
double txQueryPerformance() tx_nodiscard
Оценивает скорость работы компьютера.
bool txAlphaBlend(HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource=0, double ySource=0, double alpha=1.0)
Копирует изображение с одного холста (контекста рисования, DC) на другой с учетом полупрозрачности.
COLORREF txGetFillColor(HDC dc=txDC()) tx_nodiscard
Возвращает текущий цвет заполнения фигур.
bool txDeleteDC(HDC dc)
Уничтожает холст (контекст рисования, DC) в памяти.
const COLORREF TX_white
BLM-compatible name for this color.
Definition: TXLib.h:1485
bool txTextOut(double x, double y, const char text[], HDC dc=txDC())
Рисует текст.
bool txTransparentBlt(HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource=0, double ySource=0, COLORREF transColor=TX_BLACK)
Копирует изображение с одного холста (контекста рисования, DC) на другой с учетом прозрачности.
const COLORREF TX_CYAN
Бирюзовый цвет.
Definition: TXLib.h:1466
bool txChord(double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc=txDC())
Рисует хорду эллипса.
const COLORREF TX_TRANSPARENT
Прозрачный цвет. Отключает рисование. //-V112.
Definition: TXLib.h:1482
bool txArc(double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc=txDC())
Рисует дугу эллипса.
HDC txUseAlpha(HDC image)
Пересчитывает цвета пикселей с учетом прозрачности (переводит цвета в формат Premultiplied Alpha).
const COLORREF TX_YELLOW
Желтый цвет.
Definition: TXLib.h:1480
SIZE txGetTextExtent(const char text[], HDC dc=txDC()) tx_nodiscard
Вычисляет размеры текстовой надписи.
const COLORREF TX_LIGHTGRAY
Светло-серый цвет.
Definition: TXLib.h:1473
HFONT txSelectFont(const char name[], double sizeY, double sizeX=-1, int bold=FW_DONTCARE, bool italic=false, bool underline=false, bool strikeout=false, double angle=0, HDC dc=txDC())
Выбирает текущий шрифт, его размер и другие атрибуты.
HPEN txSetColor(COLORREF color, double thickness=1, HDC dc=txDC())
Создает (смешивает) цвет из трех базовых цветов (компонент).
double txSleep(double time=0)
Задерживает выполнение программы на определенное время.
const COLORREF TX_PINK
Розовый гламурный :)
Definition: TXLib.h:1479
COLORREF txHSL2RGB(COLORREF hslColor) tx_nodiscard
Преобразует цвет из формата HSL в формат RGB.
bool txBitBlt(HDC destImage, double xDest, double yDest, double width, double height, HDC sourceImage, double xSource=0, double ySource=0, unsigned operation=SRCCOPY)
Копирует изображение с одного холста (контекста рисования, DC) на другой.
HDC & txDC() tx_nodiscard
Возвращает холст (дескриптор контекста рисования, HDC) окна рисования TXLib.
HDC txCreateDIBSection(double sizeX, double sizeY, RGBQUAD **pixels=NULL) tx_nodiscard
Создает аппаратно-независимый дополнительный холст (контекст рисования, Device Context, DC) в памяти с возможностью прямого доступа к нему как к массиву.
bool txClear(HDC dc=txDC())
Стирает холст текущим цветом заполнения.
unsigned txSetConsoleAttr(unsigned colors=0x07)
Устанавливает цветовые атрибуты консоли.
LOGFONT * txFontExist(const char name[]) tx_nodiscard
Ищет шрифт по его названию.
int txEnd()
Разблокирует обновление окна, заблокированное функцией txBegin().
bool txFloodFill(double x, double y, COLORREF color=TX_TRANSPARENT, DWORD mode=FLOODFILLSURFACE, HDC dc=txDC())
Заливает произвольный контур текущим цветом заполнения.
bool txPie(double x0, double y0, double x1, double y1, double startAngle, double totalAngle, HDC dc=txDC())
Рисует сектор эллипса.
const COLORREF TX_WHITE
Белый цвет.
Definition: TXLib.h:1481
COLORREF txGetPixel(double x, double y, HDC dc=txDC()) tx_nodiscard
Возвращает текущий цвет точки (пикселя) на экране.
bool txIDontWantToHaveAPauseAfterMyProgramBeforeTheWindowWillClose_AndIWillNotBeAskingWhereIsMyPicture()
Делает нечто иногда удобное. См. название функции.
const COLORREF TX_RED
Темно-красный цвет. Слишком темный.
Definition: TXLib.h:1467
const COLORREF TX_BROWN
Коричневый цвет. Некрасивый. Do it yourself with RGB().
Definition: TXLib.h:1469
HDC txCreateCompatibleDC(double sizeX, double sizeY, HBITMAP bitmap=NULL, RGBQUAD **pixels=NULL) tx_nodiscard
Создает дополнительный холст (контекст рисования, Device Context, DC) в памяти.
const COLORREF TX_LIGHTRED
Светло-красный цвет. Не самого лучшего оттенка.
Definition: TXLib.h:1477
bool txTextCursor(bool blink=true)
Запрещает или разрешает рисование мигающего курсора в окне.
bool txCircle(double x, double y, double r)
Рисует окружность или круг.
const COLORREF TX_BLUE
Темно-синий цвет. Плохо виден.
Definition: TXLib.h:1464
const COLORREF TX_HUE
Цветовой тон цвета в модели HSL, [0; 255].
Definition: TXLib.h:1489
bool txSetDefaults(HDC dc=txDC())
Установка параметров рисования по умолчанию.
const COLORREF TX_LIGHTMAGENTA
Светло-малиновый цвет. Еще менее лучшего оттенка.
Definition: TXLib.h:1478
int txGetExtentY(HDC dc=txDC()) tx_nodiscard
Возвращает высоту окна или холста.
bool txLine(double x0, double y0, double x1, double y1, HDC dc=txDC())
Рисует линию.
bool txEllipse(double x0, double y0, double x1, double y1, HDC dc=txDC())
Рисует эллипс.
unsigned txVersionNumber() tx_nodiscard
Возвращает номер версии библиотеки.
const COLORREF TX_LIGHTCYAN
Светло-бирюзовый цвет.
Definition: TXLib.h:1476
COLORREF txGetColor(HDC dc=txDC()) tx_nodiscard
Возвращает текущий цвет линий и текста.
int txGetExtentX(HDC dc=txDC()) tx_nodiscard
Возвращает ширину окна или холста.
bool txSelectObject(HGDIOBJ obj, HDC dc=txDC())
Устанавливает текущий активный объект GDI.
int txGetTextExtentY(const char text[], HDC dc=txDC()) tx_nodiscard
Вычисляет высоту текстовой надписи.
unsigned txExtractColor(COLORREF color, COLORREF component) tx_nodiscard
Извлекает цветовую компоненту (цветовой канал) из смешанного цвета.
const COLORREF TX_GRAY
Серый цвет.
Definition: TXLib.h:1471
void txDrawMan(int x, int y, int sizeX, int sizeY, COLORREF color, double handL, double handR, double twist, double head, double eyes, double wink, double crazy, double smile, double hair, double wind)
Рисует человечка.
Definition: TXLib.h:2172
bool txPolygon(const POINT points[], int numPoints, HDC dc=txDC())
Рисует ломаную линию или многоугольник.
const COLORREF TX_BLACK
Названия предопределенных цветов.
Definition: TXLib.h:1463
unsigned txGetConsoleAttr() tx_nodiscard
Возвращает текущие цветовые атрибуты консоли.
HBRUSH txSetFillColor(COLORREF color, HDC dc=txDC())
Устанавливает текущий цвет заполнения фигур.
int txGetTextExtentX(const char text[], HDC dc=txDC()) tx_nodiscard
Вычисляет ширину текстовой надписи.
const COLORREF TX_NULL
Прозрачный цвет. Отключает рисование.
Definition: TXLib.h:1483
void txRedrawWindow()
Обновляет изображение в окне TXLib вручную.
POINT txGetConsoleExtent()
Возвращает размер консоли.
const COLORREF TX_ORANGE
Оранжевый цвет.
Definition: TXLib.h:1470
int txBegin()
Блокирует обновление изображения окна, во избежание мигания.
POINT txSetConsoleCursorPos(double x, double y)
Устанавливает позицию мигающего курсора консоли.
const COLORREF TX_MAGENTA
Темно-малиновый цвет.
Definition: TXLib.h:1468
const char * txVersion() tx_nodiscard
Возвращает строку с информацией о текущей версии библиотеки.
bool txTriangle(double x1, double y1, double x2, double y2, double x3, double y3)
Функция, которая должна бы рисовать треугольник.
Definition: TXLib.h:2098
bool txDrawText(double x0, double y0, double x1, double y1, const char text[], unsigned format=DT_CENTER|DT_VCENTER|DT_WORDBREAK|DT_WORD_ELLIPSIS, HDC dc=txDC())
Рисует текст, размещенный в прямоугольной области.
HWND txWindow() tx_nodiscard
Возвращает дескриптор окна рисования
bool txSetPixel(double x, double y, COLORREF color, HDC dc=txDC())
Рисует пиксель (точку на экране).
HWND txCreateWindow(double sizeX, double sizeY, bool centered=true)
Создание окна рисования
int txUpdateWindow(int update=true)
Разрешает или запрещает автоматическое обновление изображения в окне.
bool In(Tx x, Ta a, Tb b) tx_nodiscard tx_deprecated
Проверка, находится ли параметр х внутри замкнутого интервала [a; b].
#define verify
Выполняет команду (вычисляет выражение) и проверяет результат.
Definition: TXLib.h:5013
bool txPlaySound(const char filename[]=NULL, DWORD mode=SND_ASYNC)
Воспроизводит звуковой файл.
WNDPROC txSetWindowsHook(WNDPROC wndProc=NULL)
Устанавливает альтернативную функцию обработки оконных сообщений Windows (оконную функцию) для окна TXLib.
#define TX_COMMAND_MAP
Начало карты команд (Command map) в карте сообщений.
Definition: TXLib.h:6775
int txOutputDebugPrintf(const char format[],...) tx_printfy(1)
Выводит всплывающее сообщение в системном трее.
#define MIN(a, b)
Возвращает минимальное из двух чисел
Definition: TXLib.h:4608
intptr_t txPlayVideo(int x, int y, int width, int height, const char fileName[], double zoom=0, double gain=1, HWND wnd=txWindow())
Проигрывает видео.
#define TX_ERROR(...)
Выводит развернутое диагностическое сообщение.
Definition: TXLib.h:5043
#define TX_END_MESSAGE_MAP
Завершитель карты сообщений.
Definition: TXLib.h:6804
HRESULT txSetProgress(double percent, unsigned type=2, HWND wnd=NULL)
Устанавливает Progress bar окна на панели задач. @strike Весело и вкусно @endstrike Красиво и иногда полезно.
bool txLock(bool wait=true)
Блокирует холст (контекст рисования).
void tx_fpreset()
Переинициализирует математический сопроцессор
T max(const T &a, const T &b)
Функциональная версия макроса MAX.
Definition: TXLib.h:4585
double txSqr(double x)
Очень удобное возведение числа в квадрат.
Definition: TXLib.h:4704
bool txGetAsyncKeyState(int key)
Проверяет, нажата ли указанная клавиша.
#define sizearr(arr)
Добрый дядюшка Принтф. Теперь шаболонный.
Definition: TXLib.h:4394
#define asserted
Выводит диагностическое сообщение в случае нулевого или ложного результата.
Definition: TXLib.h:4968
bool txUnlock()
Разблокирует холст
int random(int range) tx_deprecated
Генератор случайных чисел
#define __TX_FUNCTION__
Имя текущей функции
Definition: TXLib.h:285
#define TX_DEBUG_ERROR(...)
Выводит развернутое диагностическое сообщение в отладочном режиме.
Definition: TXLib.h:5071
T min(const T &a, const T &b)
Функциональная версия макроса MIN.
Definition: TXLib.h:4611
#define ROUND(x)
Округляет число до целого
Definition: TXLib.h:4635
int txPause(const char *message,...) tx_printfy(1)
Приостанавливает программу до нажатия на любую клавишу.
int txSpeak(const char *text,...) tx_printfy(1)
Читает @strike мысли @endstrike текст вслух.
int txRegQuery(const char *keyName, const char *valueName, void *value, size_t szValue)
Читает информацию из реестра Windows.
#define TX_HANDLE(id)
Заголовок обработчика сообщения (Message handler) карты сообщений.
Definition: TXLib.h:6749
#define ZERO(type)
Обнулитель типов, не имеющих конструкторов
Definition: TXLib.h:4811
const int _TX_CODEPAGE
Меняет кодовую страницу консоли и локаль стандартной библиотеки С++.
Definition: TXLib.h:5574
const double txPI
Число Пи
Definition: TXLib.h:4673
#define TX_BEGIN_MESSAGE_MAP()
Заголовок карты сообщений (Message Map).
Definition: TXLib.h:6719
#define MAX(a, b)
Возвращает максимальное из двух чисел
Definition: TXLib.h:4582
int txMessageBox(const char text[]="Муаххаха! :)", const char header[]="TXLib сообщает", unsigned flags=MB_ICONINFORMATION|MB_OKCANCEL)
Выводит различные сообщения в окне с помощью функции MessageBox.
std::string txDemangle(const char *mangledName)
Преобразует декорированное имя С++ в название типа.
#define txGDI(command, dc)
Вызывает функции Win32 GDI с автоматической блокировкой и разблокировкой.
Definition: TXLib.h:5545
unsigned txMouseButtons() tx_nodiscard
Возвращает состояние Кнопок Мыши!
POINT txMousePos() tx_nodiscard
Возвращает позицию Мыши!
double txMouseY() tx_nodiscard
Возвращает Y-Координату Мыши!
double txMouseX() tx_nodiscard
Возвращает X-Координату Мыши!
#define _TX_EXCEPTIONS_LIMIT
Максимальное количество исключений в программе.
Definition: TXLib.h:5896
int _txWatchdogTimeout
Лимит времени на завершение программы, начиная от завершения функции main() или от вызова exit(), в мс.
Definition: TXLib.h:5992
#define _TX_WAITABLE_PARENTS
Список запускающих программ, которые ждут нажатия клавиши после завершения процесса TXLib.
Definition: TXLib.h:5942
const unsigned _TX_BUFSIZE
Размеры внутренних статических строковых буферов TXLib.
Definition: TXLib.h:5884
#define _TX_BUILDMODE
Имя режима сборки
Definition: TXLib.h:236
#define _TX_MODULE
Имя модуля TXLib. Входит в диагностические сообщения.
Definition: TXLib.h:166
int _txWindowStyle
Стиль графического окна библиотеки.
Definition: TXLib.h:5758
char _txLogName[MAX_PATH]
Имя лог-файла TXLib.
Definition: TXLib.h:5628
#define _TX_VER
Текущая версия библиотеки.
Definition: TXLib.h:145
const int _TX_TIMEOUT
Макрос, разрешающий использовать TXLib вместе с графической библиотекой SFML
Definition: TXLib.h:5811
const unsigned _TX_STACKSIZE
Минимальный размер стека для потоков программы.
Definition: TXLib.h:5888
#define TX_CONSOLE_MODE
Режим отображения консольного окна. Допустимы любые флаги функции ShowWindow.
Definition: TXLib.h:5727
bool _txProcessSystemWarnings
Если определено, не исключать адреса без отладочной информации из трассировок стека.
Definition: TXLib.h:5919
const unsigned _TX_HUGEBUFSIZE
Размеры очень больших статических буферов.
Definition: TXLib.h:5886
#define _TX_ALLOW_KILL_PARENT
Разрешать принудительное завершение вызывающих программ, ждущих нажатия клавиш после завершения TXLib.
Definition: TXLib.h:5975
const unsigned _TX_BIGBUFSIZE
Размеры больших статических буферов.
Definition: TXLib.h:5885
#define _TX_NOINIT
Запрет ранней инициализации TXLib.
Definition: TXLib.h:5675
unsigned _txCursorBlinkInterval
Интервал мигания курсора консоли (мс)
Definition: TXLib.h:5771
bool(* _txSwapBuffers)(HDC dest, int xDest, int yDest, int wDest, int hDest, HDC src, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rOp)
Указатель на функцию, выводящую изображение непосредственно в окно TXLib во время обработки WM_PAINT.
Definition: TXLib.h:5871
#define TX_CONSOLE_FONT
Шрифт консоли
Definition: TXLib.h:5739
#define __TX_COMPILER__
Имя и версия текущего компилятора
Definition: TXLib.h:203
unsigned _txWindowUpdateInterval
Интервал обновления холста (мс)
Definition: TXLib.h:5785
#define _TX_FATAL_EXCEPTIONS_LIMIT
Максимальное количество фатальных исключений.
Definition: TXLib.h:5900
Definition: TXLib.h:4855
Definition: flags_work.h:10
Класс для описания элемента диалогового окна (контрола)
Definition: TXLib.h:6542
short sx
Размер по X.
Definition: TXLib.h:6548
short y
Координата нижнего правого угла
Definition: TXLib.h:6547
CONTROL wndclass
Тип контрола
Definition: TXLib.h:6543
const char * font
Шрифт диалогового окна
Definition: TXLib.h:6552
short x
Координата верхнего левого угла
Definition: TXLib.h:6546
const char * caption
Название или текст
Definition: TXLib.h:6544
DWORD style
Стиль контрола
Definition: TXLib.h:6550
WORD id
Идентификатор контрола
Definition: TXLib.h:6545
short sy
Размер по Y.
Definition: TXLib.h:6549
WORD fontsize
Размер шрифта диалогового окна
Definition: TXLib.h:6553
Базовый класс для диалоговых окон.
Definition: TXLib.h:6490
intptr_t dialogBox(WORD resource)
Запускает диалоговое окно.
txDialog()
Конструктор.
virtual ~txDialog()
Деструктор.
Definition: TXLib.h:6587
static intptr_t CALLBACK DialogProc_(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
Настоящая диалоговая функция (не txDialog::dialogProc(), т.к. функция окна in32 должна быть статической).
virtual int dialogProc(HWND _wnd, UINT _msg, WPARAM _wParam, LPARAM _lParam)
Функция обработки сообщений диалогового окна.
txDialog(const Layout *layout)
Конструктор.
intptr_t dialogBox(const Layout *layout=NULL, size_t bufsize=0)
Запускает диалоговое окно.
const Layout * setLayout(const Layout *layout)
Устанавливает текущий макет диалогового окна.